//`timescale 1ns / 1ns
//defines.v
`define YSYX210745_RST        1'b1

`define YSYX210745_ZERO_WORD  64'h00000000_00000000
`define YSYX210745_PC_START   64'h00000000_30000000     
`define YSYX210745_REG_BUS    4  : 0
`define YSYX210745_REG_WIDTH  63 : 0
`define YSYX210745_RAM_BUS    63 : 0
`define YSYX210745_RAM_WIDTH  63 : 0

`define YSYX210745_REG_ADDR_0 5'b00000   


`define YSYX210745_AXI_ADDR_WIDTH      64
`define YSYX210745_AXI_DATA_WIDTH      64
`define YSYX210745_AXI_ID_WIDTH        4
`define YSYX210745_AXI_USER_WIDTH      1

`define YSYX210745_SIZE_B              2'b00
`define YSYX210745_SIZE_H              2'b01
`define YSYX210745_SIZE_W              2'b10
`define YSYX210745_SIZE_D              2'b11

`define YSYX210745_REQ_READ            1'b0
`define YSYX210745_REQ_WRITE           1'b1

`define YSYX210745_RISCV_PRIV_MODE_U   0
`define YSYX210745_RISCV_PRIV_MODE_S   1
`define YSYX210745_RISCV_PRIV_MODE_M   3

`define YSYX210745_STALL_NONE          3'b000
`define YSYX210745_STALL_IF            3'b001
`define YSYX210745_STALL_ID            3'b010
`define YSYX210745_STALL_EXE           3'b011
`define YSYX210745_STALL_MEM           3'b100

//clint 
`define YSYX210745_MTIME_ADDR     64'h00000000_0200bff8
`define YSYX210745_MTIMECMP_ADDR  64'h00000000_02004000

//inst_defines.v
//opcode

`define YSYX210745_R_type             7'b0110011
`define YSYX210745_R_type_extend      7'b0111011
`define YSYX210745_I_type             7'b0010011
`define YSYX210745_I_type_extend      7'b0011011  
`define YSYX210745_I_type_load        7'b0000011
`define YSYX210745_S_type             7'b0100011
`define YSYX210745_B_type             7'b1100011
`define YSYX210745_INST_JAL           7'b1101111
`define YSYX210745_INST_JALR          7'b1100111
`define YSYX210745_INST_FENCE         7'b0001111
`define YSYX210745_INST_LUI           7'b0110111
`define YSYX210745_INST_AUIPC         7'b0010111
`define YSYX210745_INST_NOP_OP        7'b0000001
`define YSYX210745_INST_FALT          7'b1101011    // 自定义falt      0x6b
`define YSYX210745_INST_PUTCH         7'b1111011    // 自定义putch     0x7b
`define YSYX210745_CSR_type           7'b1110011



//funct3
//R-type
`define YSYX210745_INST_ADDSUB        3'b000
`define YSYX210745_INST_SLL           3'b001
`define YSYX210745_INST_SLT           3'b010
`define YSYX210745_INST_SLTU          3'b011
`define YSYX210745_INST_XOR           3'b100
`define YSYX210745_INST_SRLSRA        3'b101
`define YSYX210745_INST_OR            3'b110
`define YSYX210745_INST_AND           3'b111 
//R-type-extend
`define YSYX210745_INST_ADDWSUBW      3'b000
`define YSYX210745_INST_SLLW          3'b001
`define YSYX210745_INST_SRLWSRAW      3'b101
//I-type
`define YSYX210745_INST_ADDI          3'b000
`define YSYX210745_INST_SLTI          3'b010
`define YSYX210745_INST_SLTIU         3'b011
`define YSYX210745_INST_XORI          3'b100
`define YSYX210745_INST_ORI           3'b110
`define YSYX210745_INST_ANDI          3'b111
`define YSYX210745_INST_SLLI          3'b001
`define YSYX210745_INST_SRLISRAI      3'b101
//I-type-extend
`define YSYX210745_INST_ADDIW         3'b000
`define YSYX210745_INST_SLLIW         3'b001
`define YSYX210745_INST_SRLIWSRAIW    3'b101
//L-type
`define YSYX210745_INST_LB            3'b000
`define YSYX210745_INST_LH            3'b001
`define YSYX210745_INST_LW            3'b010
`define YSYX210745_INST_LBU           3'b100
`define YSYX210745_INST_LHU           3'b101
//L-type-extend (opcpde与L-type相同)
`define YSYX210745_INST_LWU           3'b110
`define YSYX210745_INST_LD            3'b011
//B-type
`define YSYX210745_INST_BEQ           3'b000
`define YSYX210745_INST_BNE           3'b001
`define YSYX210745_INST_BLT           3'b100
`define YSYX210745_INST_BGE           3'b101
`define YSYX210745_INST_BLTU          3'b110
`define YSYX210745_INST_BGEU          3'b111
//S-type
`define YSYX210745_INST_SB            3'b000
`define YSYX210745_INST_SH            3'b001
`define YSYX210745_INST_SW            3'b010
//S-type-extend
`define YSYX210745_INST_SD            3'b011
// CSR-type
`define YSYX210745_INST_CSRRW         3'b001
`define YSYX210745_INST_CSRRS         3'b010
`define YSYX210745_INST_CSRRC         3'b011
`define YSYX210745_INST_CSRRWI        3'b101
`define YSYX210745_INST_CSRRSI        3'b110
`define YSYX210745_INST_CSRRCI        3'b111

//privilieged inst
`define YSYX210745_INST_MRET          32'h30200073
`define YSYX210745_INST_ECALL         32'h73

`define YSYX210745_INST_NOP           32'h00000001
//`define YSYX210745_INST_RET           32'h00008067
//`define YSYX210745_INST_EBREAK        32'h00100073

//aluopdefines.v
`define YSYX210745_ALUOP_NOP   6'b000000

`define YSYX210745_ALUOP_ADD   6'b000001    //ADD,ADDI
`define YSYX210745_ALUOP_SUB   6'b000010    //SUB   
`define YSYX210745_ALUOP_SLT   6'b000011    //signed比较，小于rd写入1,SLT,SLTI,
`define YSYX210745_ALUOP_SLTU  6'b000100    //unsigned比较，小于rd,写入1，SLTI,SLTIU
`define YSYX210745_ALUOP_AND   6'b000101
`define YSYX210745_ALUOP_OR    6'b000110
`define YSYX210745_ALUOP_XOR   6'b000111
`define YSYX210745_ALUOP_SLL   6'b001000    
`define YSYX210745_ALUOP_SRL   6'b001001
`define YSYX210745_ALUOP_SRA   6'b001010

`define YSYX210745_ALUOP_ADDW  6'b001011   //ADDW
`define YSYX210745_ALUOP_SUBW  6'b001100   //SUBW
`define YSYX210745_ALUOP_ADDIW 6'b001101   //ADDIW
`define YSYX210745_ALUOP_SLLW  6'b001110   //SLLW,SLLIW
`define YSYX210745_ALUOP_SRLW  6'b001111   //SRLW,SRLIW
`define YSYX210745_ALUOP_SRAW  6'b010000   //SRAW,SRAIW

`define YSYX210745_ALUOP_LB    6'b010001
`define YSYX210745_ALUOP_LH    6'b010010
`define YSYX210745_ALUOP_LW    6'b010011
`define YSYX210745_ALUOP_LD    6'b010100
`define YSYX210745_ALUOP_LBU   6'b010101
`define YSYX210745_ALUOP_LHU   6'b010110
`define YSYX210745_ALUOP_LWU   6'b010111

`define YSYX210745_ALUOP_SB    6'b011000
`define YSYX210745_ALUOP_SH    6'b011001
`define YSYX210745_ALUOP_SW    6'b011010
`define YSYX210745_ALUOP_SD    6'b011011

`define YSYX210745_ALUOP_JAL   6'b011100
`define YSYX210745_ALUOP_JALR  6'b011101
`define YSYX210745_ALUOP_LUI   6'b011110
`define YSYX210745_ALUOP_AUIPC 6'b011111

`define YSYX210745_ALUOP_BEQ   6'b100000
`define YSYX210745_ALUOP_BNE   6'b100001
`define YSYX210745_ALUOP_BLT   6'b100010
`define YSYX210745_ALUOP_BLTU  6'b100011
`define YSYX210745_ALUOP_BGE   6'b100100
`define YSYX210745_ALUOP_BGEU  6'b100101

//自定义指令
`define YSYX210745_ALUOP_FALT  6'b110000
`define YSYX210745_ALUOP_PUTCH 6'b110001

//csr
`define YSYX210745_ALUOP_CSRRW 6'b110010
`define YSYX210745_ALUOP_CSRRS 6'b110011
`define YSYX210745_ALUOP_CSRRC 6'b110100
`define YSYX210745_ALUOP_ECALL 6'b110101


//csr_defines.v
//csr am-test
`define YSYX210745_MCYCLE      12'hb00
`define YSYX210745_MINSTRET    12'hb02
//csr yield
`define YSYX210745_MSTATUS     12'h300
`define YSYX210745_MEDELEG     12'h302
`define YSYX210745_MIDELEG     12'h303
`define YSYX210745_MIE         12'h304
`define YSYX210745_MTVEC       12'h305
`define YSYX210745_MSCRATCH    12'h340
`define YSYX210745_MEPC        12'h341
`define YSYX210745_MCAUSE      12'h342
//csr/clint timer interupt
`define YSYX210745_MIP         12'h344
`define YSYX210745_MTIME       12'h701
`define YSYX210745_MTIMECMP    12'h321
//csr other
`define YSYX210745_MTVAL       12'h343



// Burst types
`define YSYX210745_AXI_BURST_TYPE_FIXED                                2'b00
`define YSYX210745_AXI_BURST_TYPE_INCR                                 2'b01
`define YSYX210745_AXI_BURST_TYPE_WRAP                                 2'b10
// Access permissions
`define YSYX210745_AXI_PROT_UNPRIVILEGED_ACCESS                        3'b000
`define YSYX210745_AXI_PROT_PRIVILEGED_ACCESS                          3'b001
`define YSYX210745_AXI_PROT_SECURE_ACCESS                              3'b000
`define YSYX210745_AXI_PROT_NON_SECURE_ACCESS                          3'b010
`define YSYX210745_AXI_PROT_DATA_ACCESS                                3'b000
`define YSYX210745_AXI_PROT_INSTRUCTION_ACCESS                         3'b100
// Memory types (AR)
`define YSYX210745_AXI_ARCACHE_DEVICE_NON_BUFFERABLE                   4'b0000
`define YSYX210745_AXI_ARCACHE_DEVICE_BUFFERABLE                       4'b0001
`define YSYX210745_AXI_ARCACHE_NORMAL_NON_CACHEABLE_NON_BUFFERABLE     4'b0010
`define YSYX210745_AXI_ARCACHE_NORMAL_NON_CACHEABLE_BUFFERABLE         4'b0011
`define YSYX210745_AXI_ARCACHE_WRITE_THROUGH_NO_ALLOCATE               4'b1010
`define YSYX210745_AXI_ARCACHE_WRITE_THROUGH_READ_ALLOCATE             4'b1110
`define YSYX210745_AXI_ARCACHE_WRITE_THROUGH_WRITE_ALLOCATE            4'b1010
`define YSYX210745_AXI_ARCACHE_WRITE_THROUGH_READ_AND_WRITE_ALLOCATE   4'b1110
`define YSYX210745_AXI_ARCACHE_WRITE_BACK_NO_ALLOCATE                  4'b1011
`define YSYX210745_AXI_ARCACHE_WRITE_BACK_READ_ALLOCATE                4'b1111
`define YSYX210745_AXI_ARCACHE_WRITE_BACK_WRITE_ALLOCATE               4'b1011
`define YSYX210745_AXI_ARCACHE_WRITE_BACK_READ_AND_WRITE_ALLOCATE      4'b1111
// Memory types (AW)
`define YSYX210745_AXI_AWCACHE_DEVICE_NON_BUFFERABLE                   4'b0000
`define YSYX210745_AXI_AWCACHE_DEVICE_BUFFERABLE                       4'b0001
`define YSYX210745_AXI_AWCACHE_NORMAL_NON_CACHEABLE_NON_BUFFERABLE     4'b0010
`define YSYX210745_AXI_AWCACHE_NORMAL_NON_CACHEABLE_BUFFERABLE         4'b0011
`define YSYX210745_AXI_AWCACHE_WRITE_THROUGH_NO_ALLOCATE               4'b0110
`define YSYX210745_AXI_AWCACHE_WRITE_THROUGH_READ_ALLOCATE             4'b0110
`define YSYX210745_AXI_AWCACHE_WRITE_THROUGH_WRITE_ALLOCATE            4'b1110
`define YSYX210745_AXI_AWCACHE_WRITE_THROUGH_READ_AND_WRITE_ALLOCATE   4'b1110
`define YSYX210745_AXI_AWCACHE_WRITE_BACK_NO_ALLOCATE                  4'b0111
`define YSYX210745_AXI_AWCACHE_WRITE_BACK_READ_ALLOCATE                4'b0111
`define YSYX210745_AXI_AWCACHE_WRITE_BACK_WRITE_ALLOCATE               4'b1111
`define YSYX210745_AXI_AWCACHE_WRITE_BACK_READ_AND_WRITE_ALLOCATE      4'b1111

`define AXI_YSYX210745_SIZE_BYTES_1                                    3'b000
`define AXI_YSYX210745_SIZE_BYTES_2                                    3'b001
`define AXI_YSYX210745_SIZE_BYTES_4                                    3'b010
`define AXI_YSYX210745_SIZE_BYTES_8                                    3'b011
`define AXI_YSYX210745_SIZE_BYTES_16                                   3'b100
`define AXI_YSYX210745_SIZE_BYTES_32                                   3'b101
`define AXI_YSYX210745_SIZE_BYTES_64                                   3'b110
`define AXI_YSYX210745_SIZE_BYTES_128                                  3'b111


module ysyx_210745(
    input                               clock,
    input                               reset,
    input                               io_interrupt,

    input                               io_master_awready,
    output		                        io_master_awvalid,
    output	[31:0]	                    io_master_awaddr,
    output	[3:0]	                    io_master_awid,
    output	[7:0]	                    io_master_awlen,
    output	[2:0]	                    io_master_awsize,
    output	[1:0]	                    io_master_awburst,
    input		                        io_master_wready,
    output		                        io_master_wvalid,
    output	[63:0]	                    io_master_wdata,
    output	[7:0]	                    io_master_wstrb,
    output		                        io_master_wlast,
    output		                        io_master_bready,
    input		                        io_master_bvalid,
    input	[1:0]	                    io_master_bresp,
    input	[3:0]	                    io_master_bid,
    input		                        io_master_arready,
    output		                        io_master_arvalid,
    output	[31:0]	                    io_master_araddr,
    output	[3:0]	                    io_master_arid,
    output	[7:0]	                    io_master_arlen,
    output	[2:0]	                    io_master_arsize,
    output	[1:0]	                    io_master_arburst,
    output		                        io_master_rready,
    input		                        io_master_rvalid,
    input	[1:0]	                    io_master_rresp,
    input	[63:0]	                    io_master_rdata,
    input		                        io_master_rlast,
    input	[3:0]	                    io_master_rid,

    output		                        io_slave_awready,   
    input		                        io_slave_awvalid,
    input	[31:0]	                    io_slave_awaddr,
    input	[3:0]	                    io_slave_awid,
    input	[7:0]	                    io_slave_awlen,
    input	[2:0]	                    io_slave_awsize,
    input	[1:0]	                    io_slave_awburst,   
    output		                        io_slave_wready,
    input		                        io_slave_wvalid,
    input	[63:0]	                    io_slave_wdata,
    input	[7:0]	                    io_slave_wstrb,
    input		                        io_slave_wlast,
    input		                        io_slave_bready,
    output		                        io_slave_bvalid,
    output	[1:0]	                    io_slave_bresp,
    output	[3:0]	                    io_slave_bid,
    output		                        io_slave_arready,
    input		                        io_slave_arvalid,
    input	[31:0]	                    io_slave_araddr,
    input	[3:0]	                    io_slave_arid,
    input	[7:0]	                    io_slave_arlen,
    input	[2:0]	                    io_slave_arsize,
    input	[1:0]	                    io_slave_arburst,   
    input		                        io_slave_rready,
    output		                        io_slave_rvalid,
    output	[1:0]	                    io_slave_rresp,
    output	[63:0]	                    io_slave_rdata,
    output		                        io_slave_rlast,
    output	[3:0]	                    io_slave_rid   
    
);

    wire        	axi_valid;
    wire            axi_ready;
    wire        	axi_req;
    wire [63:0]     axi_data_read;
    wire [63:0] 	axi_data_write;
    wire [63:0] 	axi_addr;
    wire [1:0]  	axi_size;

    wire            reset_o;

    //wire [1:0]      axi_resp;
    //wire            trans_done;

    ysyx_210745_axi_rw u_axi_rw (
        .clock                          (clock),
        .reset                          (reset_o),

        .rw_valid_i                     (axi_valid),
        .rw_ready_o                     (axi_ready),
        .rw_req_i                       (axi_req),
        .data_read_o                    (axi_data_read),
        .data_write_i                   (axi_data_write),
        .rw_addr_i                      (axi_addr),
        .rw_size_i                      (axi_size),
        //.rw_resp_o                      (axi_resp),
        //.trans_done_o                   (trans_done),

        .axi_aw_ready_i                 (io_master_awready),
        .axi_aw_valid_o                 (io_master_awvalid),
        .axi_aw_addr_o                  (io_master_awaddr),
        //.axi_aw_prot_o                  ( ),
        .axi_aw_id_o                    (io_master_awid),
        //.axi_aw_user_o                  ( ),
        .axi_aw_len_o                   (io_master_awlen),
        .axi_aw_size_o                  (io_master_awsize),
        .axi_aw_burst_o                 (io_master_awburst),
        //.axi_aw_lock_o                  ( ),
        //.axi_aw_cache_o                 ( ),
        //.axi_aw_qos_o                   ( ),
        //.axi_aw_region_o                ( ),

        .axi_w_ready_i                  (io_master_wready),
        .axi_w_valid_o                  (io_master_wvalid),
        .axi_w_data_o                   (io_master_wdata),
        .axi_w_strb_o                   (io_master_wstrb),
        .axi_w_last_o                   (io_master_wlast),
        //.axi_w_user_o                   ( ),
        
        .axi_b_ready_o                  (io_master_bready),
        .axi_b_valid_i                  (io_master_bvalid),
        //.axi_b_resp_i                   (io_master_bresp),
        //.axi_b_id_i                     (io_master_bid),
        //.axi_b_user_i                   ( ),

        .axi_ar_ready_i                 (io_master_arready),
        .axi_ar_valid_o                 (io_master_arvalid),
        .axi_ar_addr_o                  (io_master_araddr),
        //.axi_ar_prot_o                  ( ),
        .axi_ar_id_o                    (io_master_arid),
        //.axi_ar_user_o                  ( ),
        .axi_ar_len_o                   (io_master_arlen),
        .axi_ar_size_o                  (io_master_arsize),
        .axi_ar_burst_o                 (io_master_arburst),
        //.axi_ar_lock_o                  ( ),
        //.axi_ar_cache_o                 ( ),
        //.axi_ar_qos_o                   ( ),
        //.axi_ar_region_o                ( ),
        
        .axi_r_ready_o                  (io_master_rready),
        .axi_r_valid_i                  (io_master_rvalid),
        //.axi_r_resp_i                   (io_master_rresp),
        .axi_r_data_i                   (io_master_rdata),
        .axi_r_last_i                   (io_master_rlast)
        //.axi_r_id_i                     (io_master_rid)
        //.axi_r_user_i                   ( )
    );

    ysyx_210745_sync_async_reset usync_async_reset(
        .async_reset                    ( reset      ),
        .clock                          ( clock      ),
        .reset                          ( reset_o    )
    );


    ysyx_210745_cpu u_cpu(
    //ports
    .clock          		( clock          		),
    .reset          		( reset_o          		),
    .axi_valid      		( axi_valid      		),
    .axi_ready      		( axi_ready      		),
    .axi_req        		( axi_req        		),
    .axi_data_read  		( axi_data_read  		),
    .axi_data_write 		( axi_data_write 		),
    .axi_addr       		( axi_addr       		),
    .axi_size       		( axi_size       		)
    //.axi_resp       		( axi_resp       		)
  );



endmodule

module ysyx_210745_sync_async_reset(

    input async_reset,
    input clock,

    output reset
);
    reg rst_s1,rst_s2;
    assign reset =  rst_s2;

    always@(posedge clock or posedge async_reset)begin
        if(async_reset)begin
            rst_s1 <= 1;
            rst_s2 <= 1;
        end
        else begin
            rst_s1 <= 0;
            rst_s2 <= rst_s1;
        end
    end

endmodule

module ysyx_210745_cpu(

    input                               clock,
    input                               reset,

    output                              axi_valid,
    input                               axi_ready,
    output                              axi_req,
    input  [63:0]                       axi_data_read,
    output [63:0]                       axi_data_write,
    output [63:0]                       axi_addr,
    output [1:0]                        axi_size
    //input  [1:0]                        axi_resp
          
);
//if
wire                       	if_valid_o;
wire [`YSYX210745_AXI_ADDR_WIDTH-1:0] 	if_addr_o;
wire [1:0]                 	if_size_o;
//if_reg
wire [`YSYX210745_RAM_BUS] 	if_pc_i;
wire [31:0]     	if_inst_i;
wire            	if_reg_valid_i;

wire [`YSYX210745_RAM_BUS] 	if_pc_o;
wire [31:0]     	if_inst_o;
wire            	if_reg_valid_o;
//id
wire              	id_rs1_r_ena_o;
wire [`YSYX210745_REG_BUS]   	id_rs1_r_addr_o;
wire              	id_rs2_r_ena_o;
wire [`YSYX210745_REG_BUS]   	id_rs2_r_addr_o;

wire              	jump_o;
wire [`YSYX210745_RAM_BUS]   	new_pc_o;
wire                id_branch_tag_o;
//id_reg
wire [`YSYX210745_RAM_BUS]   	id_pc_i;
wire [`YSYX210745_REG_WIDTH] 	id_op1_i;
wire [`YSYX210745_REG_WIDTH] 	id_op2_i;
wire [`YSYX210745_REG_WIDTH] 	id_imm_i;
wire [5:0]        	id_aluop_i;
//wire              	id_skip_i;
wire                id_ecall_i;
wire                id_mret_i;
wire              	id_rd_w_ena_i;
wire [`YSYX210745_REG_BUS]   	id_rd_w_addr_i;
wire              	id_csr_r_ena_i;
wire              	id_csr_w_ena_i;
wire [11:0]       	id_csr_addr_i;

wire [`YSYX210745_RAM_BUS]   	id_pc_o;
//wire [31:0]         id_inst_o;
wire [`YSYX210745_REG_WIDTH] 	id_op1_o;
wire [`YSYX210745_REG_WIDTH] 	id_op2_o;
wire [`YSYX210745_REG_WIDTH] 	id_imm_o;
wire [5:0]        	id_aluop_o;
//wire              	id_skip_o;
wire				id_ecall_o;
wire                id_mret_o;
wire              	id_rd_w_ena_o;
wire [`YSYX210745_REG_BUS]   	id_rd_w_addr_o;
wire              	id_csr_r_ena_o;
wire              	id_csr_w_ena_o;
wire [11:0]       	id_csr_addr_o;
wire              	id_reg_valid_o;
//exe
wire [`YSYX210745_REG_WIDTH] 	csr_data_o;
wire                exe_data_valid_o;

//exe_reg
wire              	exe_rd_w_ena_i;
wire [`YSYX210745_REG_BUS]   	exe_rd_w_addr_i;
wire [`YSYX210745_REG_WIDTH] 	exe_rd_w_data_i;
wire [5:0]        	exe_aluop_i;
wire [`YSYX210745_RAM_BUS]   	exe_mem_addr_i;
wire [`YSYX210745_REG_WIDTH] 	exe_rs2_i;
//wire              	exe_halt_ena_i;
//wire              	exe_skip_i;

//wire [`YSYX210745_RAM_BUS]     exe_pc_o;
//wire [31:0]         exe_inst_o;
wire              	exe_rd_w_ena_o;
wire [`YSYX210745_REG_BUS]   	exe_rd_w_addr_o;
wire [`YSYX210745_REG_WIDTH] 	exe_rd_w_data_o;
wire [5:0]        	exe_aluop_o;
wire [`YSYX210745_RAM_BUS]   	exe_mem_addr_o;
wire [`YSYX210745_REG_WIDTH] 	exe_rs2_o;
//wire              	exe_halt_ena_o;
//wire              	exe_skip_o;
//wire              	exe_reg_valid_o;
//mem
wire  				clint_wr_o;
//wire  				clint_rd_o;
wire    			mtime_ena_o;
wire                mtimecmp_ena_o;
wire              	mem_read_req_o;
//wire              	mem_write_req_o;
wire              	mem_valid_o;
wire [`YSYX210745_RAM_BUS]   	mem_addr_o;
wire [1:0]        	mem_size_o;
wire [`YSYX210745_RAM_WIDTH] 	mem_data_write_o;
wire                mem_data_valid_o;

//mem_reg
wire              	mem_rd_w_ena_i;
wire [`YSYX210745_REG_BUS]   	mem_rd_w_addr_i;
wire [`YSYX210745_REG_WIDTH] 	mem_rd_w_data_i;


wire              	mem_rd_w_ena_o;
wire [`YSYX210745_REG_BUS]   	mem_rd_w_addr_o;
wire [`YSYX210745_REG_WIDTH] 	mem_rd_w_data_o;



//wb

//wb_reg

//wire [`YSYX210745_RAM_BUS]   	wb_pc_o;
//wire [31:0]           wb_inst_o;
//wire              	wb_rd_w_ena_o;
//wire [`YSYX210745_REG_BUS]   	wb_rd_w_addr_o;
//wire [`YSYX210745_REG_WIDTH] 	wb_rd_w_data_o;
//wire              	wb_halt_ena_o;
//wire              	wb_skip_o;
//wire              	wb_reg_valid_o;

//wire [`YSYX210745_REG_WIDTH] 	wb_mstatus_o;
//wire [`YSYX210745_REG_WIDTH] 	wb_mie_o;
//wire [`YSYX210745_REG_WIDTH] 	wb_mtvec_o;
//wire [`YSYX210745_REG_WIDTH] 	wb_mepc_o;
//wire [`YSYX210745_REG_WIDTH] 	wb_mcause_o;
//wire [`YSYX210745_REG_WIDTH] 	wb_mtval_o;
//wire [`YSYX210745_REG_WIDTH] 	wb_mip_o;
//wire [`YSYX210745_REG_WIDTH] 	wb_medeleg_o;
//wire [`YSYX210745_REG_WIDTH] 	wb_mideleg_o;
//wire [`YSYX210745_REG_WIDTH] 	wb_mscratch_o;
//regfile
wire [`YSYX210745_REG_WIDTH] 	rs1_data_o;
wire [`YSYX210745_REG_WIDTH] 	rs2_data_o;
//wire [`YSYX210745_REG_WIDTH] 	regs_o[0:31];
//csr_regfile
wire            clint_o;
wire [63:0] 	csr_rd_data;
//wire [63:0] 	mstatus_o;
//wire [63:0] 	mie_o;
wire [63:0]		mtvec_o;
wire [63:0] 	mepc_o;
//wire [63:0] 	mcause_o;
//wire [63:0] 	mtval_o;
//wire [63:0] 	mip_o;
//wire [63:0] 	mcycle_o;
//wire [63:0] 	minstret_o;
//wire [63:0] 	medeleg_o;
//wire [63:0] 	mideleg_o;
//wire [63:0] 	mscratch_o;
//wire [63:0] 	sstatus_o;
//clint
wire [`YSYX210745_REG_WIDTH] 	mtime_o;
wire [`YSYX210745_REG_WIDTH] 	mtimecmp_o;
wire                clint_interrupt_o;
//scu
wire [3:0] 	stall_ena_o;
wire [3:0] 	pipe_rst_o;
wire        mem_req_o;
wire  mem_stall_i, exe_stall_i, id_stall_i, if_stall_i;
wire  mem_rst_i,  exe_rst_i,   id_rst_i,   if_rst_i;
assign {mem_stall_i,exe_stall_i, id_stall_i, if_stall_i} = stall_ena_o[3:0];
assign {mem_rst_i,  exe_rst_i,   id_rst_i,   if_rst_i}   = pipe_rst_o[3:0];
//data_ctr
wire [`YSYX210745_REG_WIDTH] 	id_rs1_data_o;
wire [`YSYX210745_REG_WIDTH] 	id_rs2_data_o;
wire                id_hit_o;
//arbiter
wire        	if_ready_o;
wire [63:0] 	if_data_read_o;
wire        	mem_ready_o;
wire [63:0] 	mem_data_read_o;
//wire            arbiter_state_o;

ysyx_210745_pc u_pc(
    .clk            		( clock          		),
    .rst            		( reset              	),
    .if_ready_i     		( if_ready_o     		),
    .if_data_read_i 		( if_data_read_o     	),
    .if_valid_o     		( if_valid_o     		),
    .if_addr_o      		( if_addr_o      		),
    .if_size_o      		( if_size_o      		),
    .jump_ena_i     		( jump_o     		    ),
	.mem_req_i				( mem_req_o				),
    .new_pc_i       		( new_pc_o       		),
	.clint_i				( clint_o				),
	.ecall_i				( id_ecall_i			),
	.mret_i               	( id_mret_i				),
	.mtvec_i				( mtvec_o				),
	.mepc_i				    ( mepc_o				),
    .pc_o           		( if_pc_i               ),
    .inst_o         		( if_inst_i             ),
    .if_reg_valid_o 		( if_reg_valid_i 		)
);


ysyx_210745_if_reg u_if_reg(
	.clk            		( clock            		),
	.rst            		( reset | if_rst_i      ),
	.if_stall_i     		( if_stall_i     		),
	.if_pc_i        		( if_pc_i        		),
	.if_inst_i      		( if_inst_i      		),
	.if_reg_valid_i 		( if_reg_valid_i 		),
	.if_pc_o        		( if_pc_o        		),
	.if_inst_o      		( if_inst_o      		),
	.if_reg_valid_o 		( if_reg_valid_o 		)
);


ysyx_210745_id u_id(
	//ports
	.rst          			( reset          		),
	.instr_i      			( if_inst_o      		),
	.pc_i         			( if_pc_o         	),
	.rs1_data_i   			( id_rs1_data_o  		),
	.rs2_data_i   			( id_rs2_data_o  		),
	.rs1_r_ena_o  			( id_rs1_r_ena_o  		),
	.rs1_r_addr_o 			( id_rs1_r_addr_o 		),
	.rs2_r_ena_o  			( id_rs2_r_ena_o  		),
	.rs2_r_addr_o 			( id_rs2_r_addr_o 		),
	.rd_w_ena_o   			( id_rd_w_ena_i   		),
	.rd_w_addr_o  			( id_rd_w_addr_i  		),
	.csr_r_ena_o  			( id_csr_r_ena_i  		),
	.csr_w_ena_o  			( id_csr_w_ena_i  		),
	.csr_addr_o   			( id_csr_addr_i   		),
	.op1_o        			( id_op1_i        		),
	.op2_o        			( id_op2_i        		),
	.imm_o        			( id_imm_i        		),
	.aluop_o      			( id_aluop_i      		),
	.pc_o         			( id_pc_i         		),
	.jump_o       			( jump_o       		    ),
	.new_pc_o     			( new_pc_o     		    ),
	//.skip_id_o    			( id_skip_i    		    ),
	.id_branch_tag_o		( id_branch_tag_o       ),
	.ecall_o				( id_ecall_i			),
	.mret_o					( id_mret_i				)
);


ysyx_210745_id_reg u_id_reg(
	//ports
	.clk            		( clock            		),
	.rst            		( reset|id_rst_i|clint_o),
	.id_stall_i     		( id_stall_i     		),
	.id_pc_i        		( id_pc_i        		),
	//.id_inst_i              ( if_inst_o             ),
	.id_op1_i       		( id_op1_i       		),
	.id_op2_i       		( id_op2_i       		),
	.id_imm_i       		( id_imm_i       		),
	.id_aluop_i     		( id_aluop_i     		),
	//.id_skip_i      		( id_skip_i      		),
	.id_ecall_i				( id_ecall_i			),
	.id_mret_i				( id_mret_i				),
	.id_rd_w_ena_i  		( id_rd_w_ena_i  		),
	.id_rd_w_addr_i 		( id_rd_w_addr_i 		),
	.id_csr_r_ena_i			( id_csr_r_ena_i		),
	.id_csr_w_ena_i 		( id_csr_w_ena_i 		),
	.id_csr_addr_i  		( id_csr_addr_i  		),
	.id_reg_valid_i 		( if_reg_valid_o 		),
	.id_pc_o        		( id_pc_o        		),
	//.id_inst_o              ( id_inst_o             ),
	.id_op1_o       		( id_op1_o       		),
	.id_op2_o       		( id_op2_o       		),
	.id_imm_o       		( id_imm_o       		),
	.id_aluop_o     		( id_aluop_o     		),
	//.id_skip_o      		( id_skip_o      		),
	.id_ecall_o				( id_ecall_o			),
	.id_mret_o              ( id_mret_o				),
	.id_rd_w_ena_o  		( id_rd_w_ena_o  		),
	.id_rd_w_addr_o 		( id_rd_w_addr_o 		),
	.id_csr_r_ena_o		    ( id_csr_r_ena_o		),
	.id_csr_w_ena_o 		( id_csr_w_ena_o 		),
	.id_csr_addr_o  		( id_csr_addr_o  		),
	.id_reg_valid_o 		( id_reg_valid_o 		)
);



ysyx_210745_exe u_exe(
	//ports
	.clk         			( clock         		),
	.rst         			( reset         		),
	.pc_i        			( id_pc_o        		),
	.op1_i       			( id_op1_o       		),
	.op2_i       			( id_op2_o       		),
	.imm_i       			( id_imm_o       		),
	.aluop_i     			( id_aluop_o     		),
	//.skip_id_i   			( id_skip_o   		    ),
	.id_reg_valid_i			( id_reg_valid_o        ),
	.rd_w_ena_i  			( id_rd_w_ena_o  		),
	.rd_w_addr_i 			( id_rd_w_addr_o 		),
	.csr_data_i  			( csr_rd_data  		    ),
	.rd_w_ena_o  			( exe_rd_w_ena_i  		),
	.rd_w_addr_o 			( exe_rd_w_addr_i 		),
	.rd_data_o   			( exe_rd_w_data_i   	),
	.csr_data_o  			( csr_data_o  			),
	.aluop_o     			( exe_aluop_i     		),
	.mem_addr_o  			( exe_mem_addr_i  		),
	.rs2_o       			( exe_rs2_i       		),
	//.halt_ena_o  			( exe_halt_ena_i  		),
	//.skip_exe_o  			( exe_skip_i  			),
	.exe_data_valid_o		( exe_data_valid_o      )
);



ysyx_210745_exe_reg u_exe_reg(
	//ports
	.clk             		( clock             	),
	.rst             		( reset | exe_rst_i     ),
	.exe_stall_i     		( exe_stall_i     		),
	.exe_rd_w_ena_i  		( exe_rd_w_ena_i  		),
	.exe_rd_w_addr_i 		( exe_rd_w_addr_i 		),
	.exe_rd_w_data_i   		( exe_rd_w_data_i   	),
	.exe_aluop_i     		( exe_aluop_i     		),
	.exe_mem_addr_i  		( exe_mem_addr_i  		),
	.exe_rs2_i       		( exe_rs2_i       		),
	//.exe_halt_ena_i  		( exe_halt_ena_i  		),
	//.exe_skip_i      		( exe_skip_i      		),
	.exe_rd_w_ena_o  		( exe_rd_w_ena_o  		),
	.exe_rd_w_addr_o 		( exe_rd_w_addr_o 		),
	.exe_rd_w_data_o   		( exe_rd_w_data_o   	),
	.exe_aluop_o     		( exe_aluop_o     		),
	.exe_mem_addr_o  		( exe_mem_addr_o  		),
	.exe_rs2_o       		( exe_rs2_o       		)
	//.exe_halt_ena_o  		( exe_halt_ena_o  		),
	//.exe_skip_o      		( exe_skip_o      		)
);


ysyx_210745_mem u_mem(
	//ports
	.rst              		( reset              	),
	.rd_w_ena_i       		( exe_rd_w_ena_o       	),
	.rd_w_addr_i      		( exe_rd_w_addr_o      	),
	.rd_w_data_i      		( exe_rd_w_data_o      	),
	.aluop_i          		( exe_aluop_o          	),
	.mem_addr_i       		( exe_mem_addr_o       	),
	.rs2_i            		( exe_rs2_o            	),
	//.halt_ena_i       		( exe_halt_ena_o       	),
	//.skip_exe_i        		( exe_skip_o        	),
	.mtime_i				( mtime_o				),
	.mtimecmp_i				( mtimecmp_o			),
    //.clint_rd_o				( clint_rd_o			),
	.clint_wr_o				( clint_wr_o			),
	.mtime_ena_o			( mtime_ena_o			),
	.mtimecmp_ena_o			( mtimecmp_ena_o		),
	.mem_read_req_o   		( mem_read_req_o   		),
	//.mem_write_req_o  		( mem_write_req_o  		),
	.mem_valid_o      		( mem_valid_o      		),
	.mem_ready_i      		( mem_ready_o      		),
	.mem_addr_o       		( mem_addr_o       		),
	.mem_size_o       		( mem_size_o       		),
	.mem_data_read_i  		( mem_data_read_o  		),
	.mem_data_write_o 		( mem_data_write_o 		),
	.rd_w_ena_o       		( mem_rd_w_ena_i       	),
	.rd_w_addr_o      		( mem_rd_w_addr_i      	),
	.rd_w_data_o      		( mem_rd_w_data_i      	),
	.mem_data_valid_o		( mem_data_valid_o      )
);


ysyx_210745_mem_reg u_mem_reg(
	//ports
	.clk             		( clock             	),
	.rst             		( reset | mem_rst_i   	),
	.mem_stall_i     		( mem_stall_i     		),
	.mem_rd_w_ena_i  		( mem_rd_w_ena_i  		),
	.mem_rd_w_addr_i 		( mem_rd_w_addr_i 		),
	.mem_rd_w_data_i 		( mem_rd_w_data_i 		),
	.mem_rd_w_ena_o  		( mem_rd_w_ena_o  		),
	.mem_rd_w_addr_o 		( mem_rd_w_addr_o 		),
	.mem_rd_w_data_o 		( mem_rd_w_data_o 		)

);

/*
ysyx_210745_wb u_wb(
	//ports
	.rd_w_ena_i    			( mem_rd_w_ena_o    	),
	.rd_w_addr_i   			( mem_rd_w_addr_o   	),
	.rd_w_data_i   			( mem_rd_w_data_o   	),
	.wb_halt_ena_i 			( mem_halt_ena_o 		),
	.wb_skip_i     			( mem_skip_o     		),
	.rd_w_ena_o    			( wb_rd_w_ena_i    		),
	.rd_w_addr_o   			( wb_rd_w_addr_i   		),
	.rd_w_data_o   			( wb_rd_w_data_i   		),
	.wb_halt_ena_o 			( wb_halt_ena_i 		),
	.wb_skip_o     			( wb_skip_i     		)
);


ysyx_210745_wb_reg u_wb_reg(
	//ports
	.clk            		( clock            		),
	.rst            		( reset | wb_rst_i      ),
	.wb_stall_i     		( wb_stall_i    		), //暂时不需要暂停该级流水线
	.wb_pc_i        		( mem_pc_o        		),
	.wb_inst_i              ( mem_inst_o  			),
	.wb_rd_w_ena_i  		( wb_rd_w_ena_i  		),
	.wb_rd_w_addr_i 		( wb_rd_w_addr_i 		),
	.wb_rd_w_data_i    		( wb_rd_w_data_i    	),
	.wb_halt_ena_i  		( wb_halt_ena_i  		),
	.wb_skip_i      		( wb_skip_i      		),
	.wb_reg_valid_i 		( mem_reg_valid_o 		),
	.wb_mstatus_i   		( mem_mstatus_o       	),
	.wb_mie_i       		( mem_mie_o           	),
	.wb_mtvec_i       		( mem_mtvec_o           ),
	.wb_mepc_i      		( mem_mepc_o          	),
	.wb_mcause_i    		( mem_mcause_o        	),
	.wb_mtval_i     		( mem_mtval_o         	),
	.wb_mip_i       		( mem_mip_o           	),
	.wb_medeleg_i 			( mem_medeleg_o			),
	.wb_mideleg_i 			( mem_mideleg_o			),
	.wb_mscratch_i			( mem_mscratch_o		),
	.wb_pc_o        		( wb_pc_o        		),
	.wb_inst_o              ( wb_inst_o				),
	.wb_rd_w_ena_o  		( wb_rd_w_ena_o  		),
	.wb_rd_w_addr_o 		( wb_rd_w_addr_o 		),
	.wb_rd_w_data_o    		( wb_rd_w_data_o    	),
	.wb_halt_ena_o  		( wb_halt_ena_o  		),
	.wb_skip_o      		( wb_skip_o      		),
	.wb_reg_valid_o 		( wb_reg_valid_o 		),
	.wb_mstatus_o   		( wb_mstatus_o   		),
	.wb_mie_o       		( wb_mie_o       		),
	.wb_mtvec_o       		( wb_mtvec_o       		),
	.wb_mepc_o      		( wb_mepc_o      		),
	.wb_mcause_o    		( wb_mcause_o    		),
	.wb_mtval_o     		( wb_mtval_o     		),
	.wb_mip_o       		( wb_mip_o       		),
	.wb_medeleg_o 			( wb_medeleg_o 			),
	.wb_mideleg_o 			( wb_mideleg_o 			),
	.wb_mscratch_o			( wb_mscratch_o			)

);

*/
ysyx_210745_regfile u_regfile(
	//ports
	.clk     				( clock     			),
	.rst     				( reset     			),
	.w_addr  				( mem_rd_w_addr_o  		),
	.w_data  				( mem_rd_w_data_o  		),
	.w_ena   				( mem_rd_w_ena_o   		),
	.r_addr1 				( id_rs1_r_addr_o 		),
	.r_data1 				( rs1_data_o 			),
	.r_ena1  				( id_rs1_r_ena_o  		),
	.r_addr2 				( id_rs2_r_addr_o 		),
	.r_data2 				( rs2_data_o 			),
	.r_ena2  				( id_rs2_r_ena_o  		)
	//.regs    				( regs_o    			)
);


ysyx_210745_csr_regfile u_csr_regfile(
	//ports
	.clk         			( clock         		),
	.rst         			( reset         		),
	.ecall_i				( id_ecall_o			),
	.mret_i					( id_mret_o				),
	.pc_i					( id_pc_o				),
	.if_reg_valid_i			( if_reg_valid_o		),
	.if_pc_i				( if_pc_o				),
	.clint_interrupt_i		( clint_interrupt_o		),
	.csr_rd_addr    		( id_csr_addr_o    		),
	.csr_wr_addr    		( id_csr_addr_o    		),
	.csr_rd_ena  			( id_csr_r_ena_o		),
	.csr_wr_ena  			( id_csr_w_ena_o		),
	.csr_wr_data 			( csr_data_o	 		),
	.clint_o				( clint_o				),
	.csr_rd_data 			( csr_rd_data 			),
	//.mstatus_o   			( mstatus_o   			),
	//.mie_o       			( mie_o       			),
	.mtvec_o				( mtvec_o				),
	.mepc_o      			( mepc_o      			)
	//.mcause_o    			( mcause_o    			),
	//.mtval_o     			( mtval_o     			),
	//.mip_o       			( mip_o       			),
	//.medeleg_o				( medeleg_o				),
	//.mideleg_o				( mideleg_o				),
	//.mscratch_o				( mscratch_o			),
	//.sstatus_o				( sstatus_o				)
);

ysyx_210745_clint u_clint(
	//ports
	.clk         			( clock         		),
	.rst         			( reset         		),
	//.clint_rd_i       		( clint_rd_o       		),
	.clint_wr_i       		( clint_wr_o       		),
	.mtime_ena_i      		( mtime_ena_o      		),
	.mtimecmp_ena_i   		( mtimecmp_ena_o   		),
	.mem_data_write_i 		( mem_data_write_o 		),
	.mem_size_i       		( mem_size_o       		),
	.mtime_o          		( mtime_o          		),
	.mtimecmp_o       		( mtimecmp_o       		),
	.clint_interrupt_o		( clint_interrupt_o		)
);

ysyx_210745_arbiter #(
	.ARBITER_IF  		( 1'b0 		),
	.ARBITER_MEM 		( 1'b1 		))
u_arbiter(
	//ports
	.clock            		( clock            		),
	.reset            		( reset            		),
	//.if_read_req_i    		( `YSYX210745_REQ_READ     		),
	.if_valid_i       		( if_valid_o       		),
	.if_ready_o       		( if_ready_o       		),
	.if_data_read_o   		( if_data_read_o   		),
	.if_addr_i        		( if_addr_o        		),
	.if_size          		( if_size_o          	),
	.mem_read_req_i   		( mem_read_req_o   		),
	//.mem_write_req_i  		( mem_write_req_o  		),
	.mem_valid_i      		( mem_valid_o      		),
	.mem_ready_o      		( mem_ready_o      		),
	.mem_addr_i       		( mem_addr_o       		),
	.mem_size_i       		( mem_size_o       		),
	.mem_data_read_o  		( mem_data_read_o  		),
	.mem_data_write_i 		( mem_data_write_o 		),
	.rw_valid_o       		( axi_valid       		),
	.rw_ready_i       		( axi_ready       		),
	.rw_req_o         		( axi_req         		),
	.data_read_i      		( axi_data_read         ),
	.data_write_o     		( axi_data_write     	),
	.rw_addr_o        		( axi_addr        		),
	.rw_size_o        		( axi_size        		)
	//.arbiter_state_o		( arbiter_state_o		)
);


ysyx_210745_data_ctr u_data_ctr(
	//ports
	.id_rs1_r_ena_i 		( id_rs1_r_ena_o 		),
	.id_rs2_r_ena_i 		( id_rs2_r_ena_o 		),
	.id_rs1_addr_i  		( id_rs1_r_addr_o  		),
	.id_rs2_addr_i  		( id_rs2_r_addr_o  		),
	.rs1_data_i     		( rs1_data_o     		),
	.rs2_data_i     		( rs2_data_o     		),
	.exe_w_ena_i    		( exe_rd_w_ena_i    	),
	.mem_w_ena_i    		( mem_rd_w_ena_i    	),
	.wb_w_ena_i     		( mem_rd_w_ena_o     	),
	.exe_w_addr_i   		( exe_rd_w_addr_i   	),
	.mem_w_addr_i   		( mem_rd_w_addr_i   	),
	.wb_w_addr_i    		( mem_rd_w_addr_o    	),
	.exe_data_valid_i		( exe_data_valid_o      ),
	.mem_data_valid_i		( mem_data_valid_o		),
	.exe_w_data_i   		( exe_rd_w_data_i   	),
	.mem_w_data_i   		( mem_rd_w_data_i   	),
	.wb_w_data_i    		( mem_rd_w_data_o    	),

	.id_rs1_data_o  		( id_rs1_data_o  		),
	.id_rs2_data_o  		( id_rs2_data_o  		),
	.id_hit_o 		        ( id_hit_o       		)
);


ysyx_210745_scu u_scu(
	//ports
	.if_ready_i  			( if_ready_o  			),
	.mem_ready_i 			( mem_ready_o 			),
	.mem_valid_i            ( mem_valid_o           ),
	.id_branch_tag_i		( id_branch_tag_o       ),
	.id_hit_i				( id_hit_o 				),
	.stall_ena_o 			( stall_ena_o 			),
	.pipe_rst_o  			( pipe_rst_o  			),
	.mem_req_o              ( mem_req_o 			)
);
/*
//Difftest
reg cmt_wen;
reg [7:0] cmt_wdest;
reg [`YSYX210745_REG_WIDTH] cmt_wdata;
reg [`YSYX210745_REG_WIDTH] cmt_pc;
reg [31:0] cmt_inst;
reg cmt_valid;
reg trap;
reg [7:0] trap_code;
reg [63:0] cycleCnt;
reg [63:0] instrCnt;
reg [`YSYX210745_REG_WIDTH] regs_diff [0 : 31];
reg cmt_skip;
reg cmt_clint;
reg [31:0] cmt_exception_inst;

wire [31:0] cmt_intrNO;
wire [63:0] cmt_exceptionPC;
wire [31:0] cmt_exceptionInst;

assign cmt_intrNO        = cmt_clint ? 32'd7 : 0;
assign cmt_exceptionPC   = cmt_clint ? mepc_o: 0;
assign cmt_exceptionInst = cmt_clint ? cmt_exception_inst:0;

always @(posedge clock) begin
  if (reset) begin
    {cmt_wen, cmt_wdest, cmt_wdata, cmt_pc, cmt_inst, cmt_valid, trap, trap_code, cycleCnt, instrCnt,cmt_clint,cmt_exception_inst} <= 0;
  end
  else if (~trap) begin
	cmt_wen   <= wb_rd_w_ena_o;
	cmt_wdest <= {3'b0,wb_rd_w_addr_o};    
	cmt_wdata <= wb_rd_w_data_o;    
	cmt_pc    <= wb_pc_o;
	cmt_inst  <= wb_inst_o;
	cmt_valid <= wb_reg_valid_o;
	cmt_skip  <= wb_skip_o;   
	cmt_clint <= clint_o;
	cmt_exception_inst <= if_inst_o;   


    trap <= wb_inst_o[6:0] == 7'h6b;
    trap_code <= regs_o[10][7:0];
    cycleCnt <= cycleCnt + 1;
    instrCnt <= instrCnt + {63'b0,wb_reg_valid_o};
  end
end

DifftestInstrCommit DifftestInstrCommit(
  .clock              (clock),
  .coreid             (0),
  .index              (0),
  .valid              (cmt_valid),
  .pc                 (cmt_pc),
  .instr              (cmt_inst),
  .special            (0),
  .skip               (cmt_skip),
  .isRVC              (0),
  .scFailed           (0),
  .wen                (cmt_wen),
  .wdest              (cmt_wdest),
  .wdata              (cmt_wdata)
);

DifftestArchIntRegState DifftestArchIntRegState (
  .clock              (clock),
  .coreid             (0),
  .gpr_0              (regs_o[0]),
  .gpr_1              (regs_o[1]),
  .gpr_2              (regs_o[2]),
  .gpr_3              (regs_o[3]),
  .gpr_4              (regs_o[4]),
  .gpr_5              (regs_o[5]),
  .gpr_6              (regs_o[6]),
  .gpr_7              (regs_o[7]),
  .gpr_8              (regs_o[8]),
  .gpr_9              (regs_o[9]),
  .gpr_10             (regs_o[10]),
  .gpr_11             (regs_o[11]),
  .gpr_12             (regs_o[12]),
  .gpr_13             (regs_o[13]),
  .gpr_14             (regs_o[14]),
  .gpr_15             (regs_o[15]),
  .gpr_16             (regs_o[16]),
  .gpr_17             (regs_o[17]),
  .gpr_18             (regs_o[18]),
  .gpr_19             (regs_o[19]),
  .gpr_20             (regs_o[20]),
  .gpr_21             (regs_o[21]),
  .gpr_22             (regs_o[22]),
  .gpr_23             (regs_o[23]),
  .gpr_24             (regs_o[24]),
  .gpr_25             (regs_o[25]),
  .gpr_26             (regs_o[26]),
  .gpr_27             (regs_o[27]),
  .gpr_28             (regs_o[28]),
  .gpr_29             (regs_o[29]),
  .gpr_30             (regs_o[30]),
  .gpr_31             (regs_o[31])
);

DifftestTrapEvent DifftestTrapEvent(
  .clock              (clock),
  .coreid             (0),
  .valid              (trap),
  .code               (trap_code),
  .pc                 (cmt_pc),
  .cycleCnt           (cycleCnt),
  .instrCnt           (instrCnt)
);


DifftestArchEvent DifftestArchEvent(
	//ports
	.clock         		( clock         		),
	.coreid        		( 0		        		),
	.intrNO        		( cmt_intrNO		    ),
	.cause         		( 0			         	),
	.exceptionPC   		( cmt_exceptionPC  		),
	.exceptionInst 		( cmt_exceptionInst		)
);

wire [`YSYX210745_REG_WIDTH] 	cmt_mstatus_o ;
wire [`YSYX210745_REG_WIDTH] 	cmt_mepc_o    ;
wire [`YSYX210745_REG_WIDTH] 	cmt_mtval_o   ;
wire [`YSYX210745_REG_WIDTH] 	cmt_mtvec_o   ;
wire [`YSYX210745_REG_WIDTH] 	cmt_mcause_o  ;
wire [`YSYX210745_REG_WIDTH] 	cmt_mip_o     ;
wire [`YSYX210745_REG_WIDTH] 	cmt_mie_o     ;

assign cmt_mstatus_o = cmt_clint ? mstatus_o: wb_mstatus_o ;
assign cmt_mepc_o    = cmt_clint ? mepc_o   : wb_mepc_o    ;
assign cmt_mtval_o   = cmt_clint ? mtval_o  : wb_mtval_o   ;
assign cmt_mtvec_o   = cmt_clint ? mtvec_o  : wb_mtvec_o   ;
assign cmt_mcause_o  = cmt_clint ? mcause_o : wb_mcause_o  ;
assign cmt_mip_o     = cmt_clint ? mip_o    : wb_mip_o     ;
assign cmt_mie_o     = cmt_clint ? mie_o    : wb_mie_o     ;
 
DifftestCSRState DifftestCSRState(
  .clock              (clock),
  .coreid             (0),
  .priviledgeMode     (`YSYX210745_RISCV_PRIV_MODE_M),
  .mstatus            (mstatus_o),
  .sstatus            (sstatus_o),
  .mepc               (mepc_o),
  .sepc               (0),
  .mtval              (mtval_o),
  .stval              (0),
  .mtvec              (mtvec_o),
  .stvec              (0),
  .mcause             (mcause_o),
  .scause             (0),
  .satp               (0),
  .mip                (mip_o),
  .mie                (mie_o),
  .mscratch           (mscratch_o),
  .sscratch           (0),
  .mideleg            (mideleg_o),
  .medeleg            (medeleg_o)
);

DifftestArchFpRegState DifftestArchFpRegState(
  .clock              (clock),
  .coreid             (0),
  .fpr_0              (0),
  .fpr_1              (0),
  .fpr_2              (0),
  .fpr_3              (0),
  .fpr_4              (0),
  .fpr_5              (0),
  .fpr_6              (0),
  .fpr_7              (0),
  .fpr_8              (0),
  .fpr_9              (0),
  .fpr_10             (0),
  .fpr_11             (0),
  .fpr_12             (0),
  .fpr_13             (0),
  .fpr_14             (0),
  .fpr_15             (0),
  .fpr_16             (0),
  .fpr_17             (0),
  .fpr_18             (0),
  .fpr_19             (0),
  .fpr_20             (0),
  .fpr_21             (0),
  .fpr_22             (0),
  .fpr_23             (0),
  .fpr_24             (0),
  .fpr_25             (0),
  .fpr_26             (0),
  .fpr_27             (0),
  .fpr_28             (0),
  .fpr_29             (0),
  .fpr_30             (0),
  .fpr_31             (0)
);
*/

endmodule


module ysyx_210745_pc(

    input  wire                          clk,
    input  wire                          rst,  

    input  wire                          if_ready_i,   //axi
    input  wire [63:0]                   if_data_read_i,
    output wire                          if_valid_o,      
    output reg  [`YSYX210745_AXI_ADDR_WIDTH-1:0]    if_addr_o,
    output      [1 : 0]                  if_size_o,

    input  wire                          jump_ena_i, 
    input  wire                          mem_req_i,   //pc_stall
    input  wire [`YSYX210745_RAM_BUS]               new_pc_i, 
    input  wire                          clint_i, 
    input  wire                          ecall_i,
    input  wire                          mret_i,
    input  wire [`YSYX210745_RAM_BUS]               mtvec_i, 
    input  wire [`YSYX210745_RAM_BUS]               mepc_i, 
    output wire [`YSYX210745_RAM_BUS]               pc_o,
    output wire [31 : 0]                 inst_o,
    output wire                          if_reg_valid_o

   
);

    reg  [63:0] pc;
    reg  [63:0] pc_next;
    wire if_hs_done;

    assign if_addr_o      = pc_next;
    assign pc_o           = pc_next;
    assign inst_o         = if_data_read_i[31:0];
    assign if_valid_o     = 1'b1;   
    assign if_size_o      = `YSYX210745_SIZE_W;

    assign if_hs_done     = if_ready_i && if_valid_o;
    assign if_reg_valid_o = if_hs_done & ~mem_req_i;

    always @( posedge clk ) begin
        if (rst == `YSYX210745_RST) begin
            pc <= `YSYX210745_PC_START;
            pc_next <= `YSYX210745_PC_START;
        end
        else if ( if_hs_done ) begin
            if (~mem_req_i)begin
                pc <= pc_next;
                pc_next <= pc_next + 4;
            end
            else begin
                pc <= pc;
                pc_next <= pc_next;
            end
        end
        else if(clint_i)
            pc_next <= mtvec_i;
        else if(jump_ena_i)
            pc_next <= new_pc_i;
        else if(ecall_i)
            pc_next <= mtvec_i;
        else if(mret_i)
            pc_next <= mepc_i;
        else begin
            pc <= pc;
            pc_next <= pc_next;
        end

    end


endmodule


module ysyx_210745_if_reg(
    
    input                     clk,
    input                     rst,
    input                     if_stall_i,

    input  wire [`YSYX210745_RAM_BUS]    if_pc_i,
    input  wire [31 : 0]      if_inst_i,
    input  wire               if_reg_valid_i,

    output reg  [`YSYX210745_RAM_BUS]    if_pc_o,
    output reg  [31 : 0]      if_inst_o,
    output reg                if_reg_valid_o

);

    always@(posedge clk)begin
        if(rst == `YSYX210745_RST )begin
            if_pc_o <= 0;
            if_inst_o <= 0;
            if_reg_valid_o <= 0;
        end
        else if(if_stall_i)begin
            if_pc_o <= if_pc_o;
            if_inst_o <= if_inst_o; 
            if_reg_valid_o <= if_reg_valid_o;
        end
        else begin
            if_pc_o <= if_pc_i;
            if_inst_o <= if_inst_i;
            if_reg_valid_o <= if_reg_valid_i; 
        end
    end
    //wire rd_s0 = if_inst_o == 32'h00044503 ;




endmodule


module ysyx_210745_id(
  input wire                rst,
  input wire [31 : 0]       instr_i,
  input wire [`YSYX210745_RAM_BUS]     pc_i,
  input wire [`YSYX210745_REG_WIDTH]   rs1_data_i,
  input wire [`YSYX210745_REG_WIDTH]   rs2_data_i,
  
  
  output reg                rs1_r_ena_o,
  output reg [`YSYX210745_REG_BUS]     rs1_r_addr_o,
  output reg                rs2_r_ena_o,
  output reg [`YSYX210745_REG_BUS]     rs2_r_addr_o,
  output reg                rd_w_ena_o,
  output reg [`YSYX210745_REG_BUS]     rd_w_addr_o,

  output wire               csr_r_ena_o,
  output wire               csr_w_ena_o,
  output wire [11:0]        csr_addr_o,
  
  output reg  [`YSYX210745_REG_WIDTH]  op1_o,
  output reg  [`YSYX210745_REG_WIDTH]  op2_o,
  output reg  [`YSYX210745_REG_WIDTH]  imm_o,
  output reg  [5:0]         aluop_o,
  output wire [`YSYX210745_RAM_BUS]    pc_o,

  output wire               jump_o,
  output wire [`YSYX210745_RAM_BUS]    new_pc_o,
  //output wire               skip_id_o,
  output reg                id_branch_tag_o,
  output wire               ecall_o,
  output wire               mret_o
);

reg jump;

// 指令内容提取
wire[6:0] opcode = instr_i[6:0]   ;
wire[2:0] funct3 = instr_i[14:12] ;
wire[6:0] funct7 = instr_i[31:25] ;
wire[4:0] rd 	 = instr_i[11:7]  ;
wire[4:0] rs1 	 = instr_i[19:15] ;
wire[4:0] rs2  	 = instr_i[24:20] ;
wire[11:0] csr   = instr_i[31:20] ;

assign csr_addr_o = ( ecall_o | mret_o) ? 0 : csr;
//assign skip_id_o  = ( opcode == `YSYX210745_CSR_type ) && ( csr == `YSYX210745_MCYCLE);

assign jump_o     = (jump == 1'b1 ) && (new_pc_o != pc_i + 4);
assign pc_o       = pc_i;
assign ecall_o    = instr_i == `YSYX210745_INST_ECALL;
assign mret_o     = instr_i == `YSYX210745_INST_MRET;

//译码出立即数
always @ (*) begin
    case (opcode)
        `YSYX210745_R_type, `YSYX210745_R_type_extend :
            imm_o = 0;
        `YSYX210745_I_type, `YSYX210745_I_type_extend, `YSYX210745_I_type_load, `YSYX210745_INST_JALR : 
            imm_o = {  {52{instr_i[31]}} , instr_i[31:20] };
        `YSYX210745_S_type : 
            imm_o = {  {52{instr_i[31]}} , instr_i[31:25] , instr_i[11:7] };
        `YSYX210745_B_type : 
            imm_o = {  {52{instr_i[31]}} , instr_i[7]     , instr_i[30:25] ,instr_i[11:8] ,1'b0 };
        `YSYX210745_INST_LUI, `YSYX210745_INST_AUIPC :
            imm_o = {  {33{instr_i[31]}} ,instr_i[30:12]    , 12'b0  };
        `YSYX210745_INST_JAL : 
            imm_o = {  {44{instr_i[31]}} , instr_i[19:12] , instr_i[20]  ,  instr_i[30:21],1'b0 };
        `YSYX210745_CSR_type :
            imm_o = {  {59{instr_i[19]}} , instr_i[19:15] };
        default: imm_o = 0;
    endcase
end  

//rd 写使能信号
    always @ (*) begin
        case(opcode)
            `YSYX210745_R_type, `YSYX210745_R_type_extend,`YSYX210745_I_type, `YSYX210745_I_type_extend, `YSYX210745_I_type_load, `YSYX210745_INST_JAL,`YSYX210745_INST_JALR, `YSYX210745_INST_LUI, `YSYX210745_INST_AUIPC, `YSYX210745_CSR_type  : 
                rd_w_ena_o = 1'b1;
            `YSYX210745_S_type, `YSYX210745_B_type  : 
                rd_w_ena_o = 1'b0;
            default : 
                rd_w_ena_o = 1'b0;
        endcase
    end
//csr 写使能信号, ecall和mret因为要改写多个寄存器当作特殊情况处理
    assign csr_r_ena_o = ( opcode == `YSYX210745_CSR_type ) & ~ ( ecall_o | mret_o);
    assign csr_w_ena_o = ( opcode == `YSYX210745_CSR_type ) & ~ ( ecall_o | mret_o);

//rs1 ，rs2读使能信号

    always @ (*) begin
        case(opcode)
            `YSYX210745_R_type,`YSYX210745_R_type_extend, `YSYX210745_S_type, `YSYX210745_B_type : 
                {rs1_r_ena_o, rs2_r_ena_o} = 2'b11;
            `YSYX210745_I_type, `YSYX210745_I_type_extend, `YSYX210745_I_type_load, `YSYX210745_INST_JALR ,`YSYX210745_INST_PUTCH: 
                {rs1_r_ena_o, rs2_r_ena_o} = 2'b10;
            `YSYX210745_INST_JAL, `YSYX210745_INST_LUI, `YSYX210745_INST_AUIPC  : 
                {rs1_r_ena_o, rs2_r_ena_o} = 2'b00;
            `YSYX210745_CSR_type:
                if(!funct3[2])
                    {rs1_r_ena_o, rs2_r_ena_o} = 2'b10;
                else
                    {rs1_r_ena_o, rs2_r_ena_o} = 2'b00;
            default : 
                {rs1_r_ena_o, rs2_r_ena_o} = 2'b00;
        endcase
    end
//第一个操作数
    always @ (*) begin
        if(rst == `YSYX210745_RST)
            op1_o = `YSYX210745_ZERO_WORD;
        else if(rs1_r_ena_o)
            op1_o = rs1_data_i;
        else if(!rs1_r_ena_o)
            op1_o = imm_o;
        else
            op1_o = `YSYX210745_ZERO_WORD;
    end

//第二个操作数
    always @ (*) begin
        if(rst == `YSYX210745_RST)
            op2_o = `YSYX210745_ZERO_WORD;
        else if(rs2_r_ena_o)
            op2_o = rs2_data_i;
        else if(!rs2_r_ena_o)
            op2_o = imm_o;
        else
            op2_o = `YSYX210745_ZERO_WORD;
    end

//将分支指令提前一个周期执行
    always @ (*) begin
        if(rst == `YSYX210745_RST) begin
            new_pc_o = `YSYX210745_ZERO_WORD; 
            jump   = 1'b0;
            id_branch_tag_o = 1;
        end
        else begin
            case (aluop_o)
                `YSYX210745_ALUOP_JAL : begin id_branch_tag_o = 1; jump = 1'b1; new_pc_o = pc_i + imm_o; end
                `YSYX210745_ALUOP_JALR: begin id_branch_tag_o = 1; jump = 1'b1; new_pc_o = (op1_o + imm_o) & ~64'b1; end
                `YSYX210745_ALUOP_BEQ : begin id_branch_tag_o = 1; jump = op1_o == op2_o; new_pc_o = pc_i + imm_o; end
                `YSYX210745_ALUOP_BNE : begin id_branch_tag_o = 1; jump = op1_o != op2_o; new_pc_o = pc_i + imm_o; end
                `YSYX210745_ALUOP_BLT : begin id_branch_tag_o = 1; jump = $signed(op1_o) < $signed(op2_o); new_pc_o = pc_i + imm_o; end
                `YSYX210745_ALUOP_BLTU: begin id_branch_tag_o = 1; jump = op1_o <  op2_o; new_pc_o = pc_i + imm_o; end
                `YSYX210745_ALUOP_BGE : begin id_branch_tag_o = 1; jump = $signed(op1_o) >= $signed(op2_o); new_pc_o = pc_i + imm_o; end
                `YSYX210745_ALUOP_BGEU: begin id_branch_tag_o = 1; jump = op1_o >= op2_o; new_pc_o = pc_i + imm_o; end
                
                default    : begin id_branch_tag_o = 0; jump = 1'b0; new_pc_o = `YSYX210745_ZERO_WORD; end
            endcase
        end
    end

//alu_opcode

always @ (*) begin
        if(rst == `YSYX210745_RST) begin
            rs1_r_addr_o = `YSYX210745_REG_ADDR_0;
            rs2_r_addr_o = `YSYX210745_REG_ADDR_0;
            rd_w_addr_o  = `YSYX210745_REG_ADDR_0; 
            aluop_o      = `YSYX210745_ALUOP_NOP;
            end
        else if( opcode == `YSYX210745_INST_FALT )
            begin
                rs1_r_addr_o = 5'd10;
                aluop_o = `YSYX210745_ALUOP_FALT;
            end
        else if( opcode == `YSYX210745_INST_PUTCH )
            begin
                rs1_r_addr_o = 5'd10;
                aluop_o = `YSYX210745_ALUOP_PUTCH;
            end
        else begin
            rs1_r_addr_o = rs1;
            rs2_r_addr_o = rs2;
            rd_w_addr_o  = rd;
            case (opcode)
                `YSYX210745_R_type : begin  
                    case(funct3)
                        `YSYX210745_INST_ADDSUB : begin
                            if(funct7 == 7'b0) aluop_o = `YSYX210745_ALUOP_ADD;
                            else               aluop_o = `YSYX210745_ALUOP_SUB;
                            end
                        
                        `YSYX210745_INST_SLT  : aluop_o = `YSYX210745_ALUOP_SLT;
                        `YSYX210745_INST_SLTU : aluop_o = `YSYX210745_ALUOP_SLTU;
                        `YSYX210745_INST_AND  : aluop_o = `YSYX210745_ALUOP_AND;
                        `YSYX210745_INST_OR   : aluop_o = `YSYX210745_ALUOP_OR;
                        `YSYX210745_INST_XOR  : aluop_o = `YSYX210745_ALUOP_XOR;
                        `YSYX210745_INST_SLL  : aluop_o = `YSYX210745_ALUOP_SLL;
                        `YSYX210745_INST_SRLSRA : begin
                            if(funct7[6:1] == 6'b00) aluop_o = `YSYX210745_ALUOP_SRL;
                            else                     aluop_o = `YSYX210745_ALUOP_SRA;
                            end
                        default    : aluop_o = `YSYX210745_ALUOP_NOP;    
                    endcase
                    end
                `YSYX210745_R_type_extend : begin    
                    case(funct3)
                        `YSYX210745_INST_ADDWSUBW : begin
                            if(funct7 == 7'b0) aluop_o = `YSYX210745_ALUOP_ADDW;
                            else               aluop_o = `YSYX210745_ALUOP_SUBW;
                         end   
                        `YSYX210745_INST_SLLW : aluop_o = `YSYX210745_ALUOP_SLLW;
                        `YSYX210745_INST_SRLWSRAW : begin
                            if(funct7[6:1] == 6'b00)  aluop_o = `YSYX210745_ALUOP_SRLW;
                            else                      aluop_o = `YSYX210745_ALUOP_SRAW;
                        end
                        default    : aluop_o = `YSYX210745_ALUOP_NOP;          
                    endcase
                    end
                `YSYX210745_I_type : begin  
                    case(funct3)
                        `YSYX210745_INST_ADDI  : aluop_o = `YSYX210745_ALUOP_ADD;
                        `YSYX210745_INST_SLTI  : aluop_o = `YSYX210745_ALUOP_SLT;
                        `YSYX210745_INST_SLTIU : aluop_o = `YSYX210745_ALUOP_SLTU;
                        `YSYX210745_INST_ANDI  : aluop_o = `YSYX210745_ALUOP_AND;
                        `YSYX210745_INST_ORI   : aluop_o = `YSYX210745_ALUOP_OR;
                        `YSYX210745_INST_XORI  : aluop_o = `YSYX210745_ALUOP_XOR;
                        `YSYX210745_INST_SLLI  : aluop_o = `YSYX210745_ALUOP_SLL;
                        `YSYX210745_INST_SRLISRAI : begin
                            if(funct7[6:1] == 6'b00) aluop_o = `YSYX210745_ALUOP_SRL;
                            else                     aluop_o = `YSYX210745_ALUOP_SRA;
                            end
                        default    : aluop_o = `YSYX210745_ALUOP_NOP;    
                    endcase
                    end
                `YSYX210745_I_type_extend : begin    
                    case(funct3)
                        `YSYX210745_INST_ADDIW : aluop_o = `YSYX210745_ALUOP_ADDW; 
                        `YSYX210745_INST_SLLIW : aluop_o = `YSYX210745_ALUOP_SLLW;
                        `YSYX210745_INST_SRLIWSRAIW : begin
                            if(funct7[6:1] == 6'b00)  aluop_o = `YSYX210745_ALUOP_SRLW;
                            else                      aluop_o = `YSYX210745_ALUOP_SRAW;
                        end
                        default    : aluop_o = `YSYX210745_ALUOP_NOP;          
                    endcase
                    end
                `YSYX210745_I_type_load : begin
                    case(funct3)
                        `YSYX210745_INST_LB : aluop_o = `YSYX210745_ALUOP_LB;
                        `YSYX210745_INST_LH : aluop_o = `YSYX210745_ALUOP_LH;
                        `YSYX210745_INST_LW : aluop_o = `YSYX210745_ALUOP_LW;
                        `YSYX210745_INST_LBU: aluop_o = `YSYX210745_ALUOP_LBU;
                        `YSYX210745_INST_LHU: aluop_o = `YSYX210745_ALUOP_LHU;
                        `YSYX210745_INST_LWU: aluop_o = `YSYX210745_ALUOP_LWU;
                        `YSYX210745_INST_LD : aluop_o = `YSYX210745_ALUOP_LD;
                        default  : aluop_o = `YSYX210745_ALUOP_NOP;  
                    endcase
                    end
                `YSYX210745_S_type : begin
                    case (funct3)
                        `YSYX210745_INST_SB : aluop_o = `YSYX210745_ALUOP_SB;
                        `YSYX210745_INST_SH : aluop_o = `YSYX210745_ALUOP_SH;
                        `YSYX210745_INST_SW : aluop_o = `YSYX210745_ALUOP_SW;
                        `YSYX210745_INST_SD : aluop_o = `YSYX210745_ALUOP_SD;
                        default  : aluop_o = `YSYX210745_ALUOP_NOP;  
                    endcase
                    end
                `YSYX210745_B_type : begin
                    case (funct3)
                        `YSYX210745_INST_BEQ : aluop_o = `YSYX210745_ALUOP_BEQ;
                        `YSYX210745_INST_BNE : aluop_o = `YSYX210745_ALUOP_BNE;
                        `YSYX210745_INST_BLT : aluop_o = `YSYX210745_ALUOP_BLT;
                        `YSYX210745_INST_BGE : aluop_o = `YSYX210745_ALUOP_BGE;
                        `YSYX210745_INST_BLTU: aluop_o = `YSYX210745_ALUOP_BLTU;
                        `YSYX210745_INST_BGEU: aluop_o = `YSYX210745_ALUOP_BGEU;
                        default   : aluop_o = `YSYX210745_ALUOP_NOP; 
                    endcase
                    end
                `YSYX210745_CSR_type : begin
                    case (funct3)
                        `YSYX210745_INST_CSRRW : aluop_o = `YSYX210745_ALUOP_CSRRW;
                        `YSYX210745_INST_CSRRS : aluop_o = `YSYX210745_ALUOP_CSRRS;
                        `YSYX210745_INST_CSRRC : aluop_o = `YSYX210745_ALUOP_CSRRC;
                        `YSYX210745_INST_CSRRWI: aluop_o = `YSYX210745_ALUOP_CSRRW;
                        `YSYX210745_INST_CSRRSI: aluop_o = `YSYX210745_ALUOP_CSRRS;
                        `YSYX210745_INST_CSRRCI: aluop_o = `YSYX210745_ALUOP_CSRRC;
                        //`YSYX210745_INST_ECALL : aluop_o = `YSYX210745_ALUOP_ECALL;
                        default   : aluop_o = `YSYX210745_ALUOP_NOP; 
                    endcase
                    end
                `YSYX210745_INST_JAL : begin
                    aluop_o = `YSYX210745_ALUOP_JAL;
                    end
                `YSYX210745_INST_JALR: begin
                    aluop_o = `YSYX210745_ALUOP_JALR;
                    end
                `YSYX210745_INST_LUI : begin
                    aluop_o = `YSYX210745_ALUOP_LUI;
                    end
                `YSYX210745_INST_AUIPC: begin
                    aluop_o = `YSYX210745_ALUOP_AUIPC;
                    end
                
                `YSYX210745_INST_NOP_OP: begin
                    aluop_o = `YSYX210745_ALUOP_NOP;
                    end
                                  
                default   :
                    aluop_o = `YSYX210745_ALUOP_NOP;
            endcase 
            end
    end

endmodule


module ysyx_210745_id_reg(

    input                     clk,
    input                     rst,
    input                     id_stall_i,

    input  wire [`YSYX210745_RAM_BUS]    id_pc_i,
    //input  wire [31:0]        id_inst_i,
    input  wire [`YSYX210745_REG_WIDTH]  id_op1_i,
    input  wire [`YSYX210745_REG_WIDTH]  id_op2_i,
    input  wire [`YSYX210745_REG_WIDTH]  id_imm_i,
    input  wire [5:0]         id_aluop_i,
    //input  wire               id_skip_i,
    input  wire               id_ecall_i,
    input  wire               id_mret_i,

    input  wire               id_rd_w_ena_i,
    input  wire [`YSYX210745_REG_BUS]    id_rd_w_addr_i,
    input  wire               id_csr_r_ena_i,
    input  wire               id_csr_w_ena_i,
    input  wire [11:0]        id_csr_addr_i,

    input  wire               id_reg_valid_i,

    output reg  [`YSYX210745_RAM_BUS]    id_pc_o,
    //output reg  [31:0]        id_inst_o,
    output reg  [`YSYX210745_REG_WIDTH]  id_op1_o,
    output reg  [`YSYX210745_REG_WIDTH]  id_op2_o,
    output reg  [`YSYX210745_REG_WIDTH]  id_imm_o,
    output reg  [5:0]         id_aluop_o,
    //output reg                id_skip_o,
    output reg                id_ecall_o,
    output reg                id_mret_o,
    
    output reg                id_rd_w_ena_o,
    output reg  [`YSYX210745_REG_BUS]    id_rd_w_addr_o,
    output reg                id_csr_r_ena_o,
    output reg                id_csr_w_ena_o,
    output reg  [11:0]        id_csr_addr_o,

    output reg                id_reg_valid_o

);


    always@(posedge clk)begin
        if(rst == `YSYX210745_RST )begin
            id_pc_o         <= 0;
            //id_inst_o       <= 0;
            id_op1_o        <= 0;
            id_op2_o        <= 0;
            id_imm_o        <= 0;
            id_aluop_o      <= 0;
            //id_skip_o       <= 0;
            id_ecall_o      <= 0;
            id_mret_o       <= 0;
            id_rd_w_ena_o   <= 0;
            id_rd_w_addr_o  <= 0;
            id_csr_r_ena_o  <= 0;
            id_csr_w_ena_o  <= 0;
            id_csr_addr_o   <= 0;
            id_reg_valid_o  <= 0;
        end
        else if(id_stall_i)begin
            id_pc_o         <= id_pc_o;
            //id_inst_o       <= id_inst_o;
            id_op1_o        <= id_op1_o;
            id_op2_o        <= id_op2_o;
            id_imm_o        <= id_imm_o;
            id_aluop_o      <= id_aluop_o;
            //id_skip_o       <= id_skip_o;
            id_ecall_o      <= id_ecall_o;
            id_mret_o       <= id_mret_o;
            id_rd_w_ena_o   <= id_rd_w_ena_o;
            id_rd_w_addr_o  <= id_rd_w_addr_o;
            id_csr_r_ena_o  <= id_csr_r_ena_o;
            id_csr_w_ena_o  <= id_csr_w_ena_o;
            id_csr_addr_o   <= id_csr_addr_o;
            id_reg_valid_o  <= id_reg_valid_o;
        end
        else begin
            id_pc_o         <= id_pc_i;
            //id_inst_o       <= id_inst_i;
            id_op1_o        <= id_op1_i;
            id_op2_o        <= id_op2_i;
            id_imm_o        <= id_imm_i;
            id_aluop_o      <= id_aluop_i;
            //id_skip_o       <= id_skip_i;
            id_ecall_o      <= id_ecall_i;
            id_mret_o       <= id_mret_i;
            id_rd_w_ena_o   <= id_rd_w_ena_i;
            id_rd_w_addr_o  <= id_rd_w_addr_i;
            id_csr_r_ena_o  <= id_csr_r_ena_i;
            id_csr_w_ena_o  <= id_csr_w_ena_i;
            id_csr_addr_o   <= id_csr_addr_i;
            id_reg_valid_o  <= id_reg_valid_i;
        end
    end




endmodule



module ysyx_210745_exe(
    input wire clk,
    input wire rst,

    input  wire    [`YSYX210745_RAM_BUS]         pc_i,
    input  wire    [`YSYX210745_REG_WIDTH]       op1_i,
    input  wire    [`YSYX210745_REG_WIDTH]       op2_i,
    input  wire    [`YSYX210745_REG_WIDTH]       imm_i,
    input  wire    [5 : 0]            aluop_i,
    //input  wire                       skip_id_i,
    input  wire                       id_reg_valid_i,


    input  wire                       rd_w_ena_i,
    input  wire    [`YSYX210745_REG_BUS]         rd_w_addr_i,
  
    input  wire    [`YSYX210745_REG_WIDTH]       csr_data_i, 

    output reg                        rd_w_ena_o,
    output reg     [`YSYX210745_REG_BUS]         rd_w_addr_o, 
    output reg     [`YSYX210745_REG_WIDTH]       rd_data_o,
 
    output reg     [`YSYX210745_REG_WIDTH]       csr_data_o,    //csr寄存器写操作放在exe执行

    //访存相关
    output reg     [5 : 0]            aluop_o,
    output reg     [`YSYX210745_RAM_BUS]         mem_addr_o,
    output reg     [`YSYX210745_REG_WIDTH]       rs2_o,         //store将第二个操作数存到D-RAM


    //output reg                        halt_ena_o,
    //output wire                       skip_exe_o,
    output reg                        exe_data_valid_o                  


);
    //skip
    //reg    skip_exe;
    //wire   clint_skip;
    //assign clint_skip = (mem_addr_o == `YSYX210745_MTIMECMP_ADDR | mem_addr_o == `YSYX210745_MTIME_ADDR);
    //assign skip_exe_o = skip_exe | skip_id_i | clint_skip;

    //wire putch_tag = aluop_i == `YSYX210745_ALUOP_PUTCH;

    // 部分计算结果
    wire  [`YSYX210745_REG_WIDTH]     add_result;
    wire  [`YSYX210745_REG_WIDTH]     sub_result;
    wire  [`YSYX210745_REG_WIDTH]     sll_result;
    wire  [`YSYX210745_REG_WIDTH]     srl_result;
    wire  [`YSYX210745_REG_WIDTH]     sra_result;
    wire  [31:0]           sllw_result;
    wire  [31:0]           srlw_result;
    wire  [31:0]           sraw_result;

    wire  [`YSYX210745_REG_WIDTH]     sra_l;            //sra计算时的左边符号部分
    wire  [`YSYX210745_REG_WIDTH]     sra_r;            //sra计算时的右边移位部分
    wire  [31:0]           sraw_l;           //sraw计算时的左边符号部分
    wire  [31:0]           sraw_r;           //sraw计算时的右边移位部分

    //提前计算出一些下面会用到的结果
    assign add_result  = op1_i + op2_i;
    assign sub_result  = op1_i - op2_i;
    assign sll_result  = op1_i << op2_i[5:0]; //sll,slli
    assign srl_result  = op1_i >> op2_i[5:0]; //srl,srli
    assign sllw_result = op1_i[31:0] << op2_i[4:0]; //sllw,slliw
    assign srlw_result = op1_i[31:0] >> op2_i[4:0]; //srlw,srliw
    //算数右移计算
    assign sra_l       = 64'hffff_ffff_ffff_ffff >> op2_i[5:0];
    assign sra_r       = op1_i >> op2_i[5:0];
    assign sra_result  = (sra_l & sra_r) | ({64{op1_i[63]}} & (~sra_l));

    assign sraw_l       = 32'hffff_ffff >> op2_i[4:0];
    assign sraw_r       = op1_i[31:0] >> op2_i[4:0];
    assign sraw_result  = (sraw_l & sraw_r) | ({32{op1_i[31]}} & (~sraw_l));

    //alu
    always @ (*) begin
        rd_w_ena_o    = rd_w_ena_i;
        rd_w_addr_o   = rd_w_addr_i;
        rs2_o         = op2_i;
        aluop_o       = aluop_i;
        if(rst == `YSYX210745_RST) begin
            rd_data_o  = `YSYX210745_ZERO_WORD;
            exe_data_valid_o = 0;
        end
        else begin
            case (aluop_i)
                `YSYX210745_ALUOP_NOP : begin exe_data_valid_o = 1'b1; rd_data_o = `YSYX210745_ZERO_WORD; end
                `YSYX210745_ALUOP_ADD : begin exe_data_valid_o = 1'b1; rd_data_o = add_result; end
                `YSYX210745_ALUOP_SUB : begin exe_data_valid_o = 1'b1; rd_data_o = sub_result; end
                `YSYX210745_ALUOP_ADDW: begin exe_data_valid_o = 1'b1; rd_data_o = {{32{add_result[31]}}, add_result[31:0] }; end
                `YSYX210745_ALUOP_SUBW: begin exe_data_valid_o = 1'b1; rd_data_o = {{32{sub_result[31]}}, sub_result[31:0] }; end        
                `YSYX210745_ALUOP_SLT : begin exe_data_valid_o = 1'b1; rd_data_o = {63'b0,($signed(op1_i) < $signed(op2_i))}; end
                `YSYX210745_ALUOP_SLTU: begin exe_data_valid_o = 1'b1; rd_data_o = {63'b0,(op1_i < op2_i)}; end
                `YSYX210745_ALUOP_AND : begin exe_data_valid_o = 1'b1; rd_data_o = op1_i & op2_i; end
                `YSYX210745_ALUOP_OR  : begin exe_data_valid_o = 1'b1; rd_data_o = op1_i | op2_i; end
                `YSYX210745_ALUOP_XOR : begin exe_data_valid_o = 1'b1; rd_data_o = op1_i ^ op2_i;end
                `YSYX210745_ALUOP_SLL : begin exe_data_valid_o = 1'b1; rd_data_o = sll_result; end
                `YSYX210745_ALUOP_SRL : begin exe_data_valid_o = 1'b1; rd_data_o = srl_result; end
                `YSYX210745_ALUOP_SRA : begin exe_data_valid_o = 1'b1; rd_data_o = sra_result; end
                `YSYX210745_ALUOP_SLLW: begin exe_data_valid_o = 1'b1; rd_data_o = {{32{sllw_result[31]}}, sllw_result[31:0] }; end    
                `YSYX210745_ALUOP_SRLW: begin exe_data_valid_o = 1'b1; rd_data_o = {{32{srlw_result[31]}}, srlw_result[31:0] }; end                 
                `YSYX210745_ALUOP_SRAW: begin exe_data_valid_o = 1'b1; rd_data_o = {{32{sraw_result[31]}}, sraw_result[31:0] }; end

                `YSYX210745_ALUOP_LUI : begin exe_data_valid_o = 1'b1; rd_data_o = imm_i; end
                `YSYX210745_ALUOP_AUIPC:begin exe_data_valid_o = 1'b1; rd_data_o = pc_i + imm_i; end

                `YSYX210745_ALUOP_JAL : begin exe_data_valid_o = 1'b1; rd_data_o = pc_i + 4; end
                `YSYX210745_ALUOP_JALR: begin exe_data_valid_o = 1'b1; rd_data_o = pc_i + 4; end

                `YSYX210745_ALUOP_CSRRW:begin exe_data_valid_o = 1'b1; rd_data_o = csr_data_i; end
                `YSYX210745_ALUOP_CSRRS:begin exe_data_valid_o = 1'b1; rd_data_o = csr_data_i; end
                `YSYX210745_ALUOP_CSRRC:begin exe_data_valid_o = 1'b1; rd_data_o = csr_data_i; end

                default    : begin exe_data_valid_o = 1'b0; rd_data_o = `YSYX210745_ZERO_WORD; end                                     
            endcase
        end
    end

    always @ (*) begin
        if(rst == `YSYX210745_RST) begin
            mem_addr_o = `YSYX210745_ZERO_WORD; 
        end
        else begin
            case (aluop_i)
                `YSYX210745_ALUOP_LB  : mem_addr_o = op1_i + imm_i;
                `YSYX210745_ALUOP_LH  : mem_addr_o = op1_i + imm_i;
                `YSYX210745_ALUOP_LW  : mem_addr_o = op1_i + imm_i;
                `YSYX210745_ALUOP_LD  : mem_addr_o = op1_i + imm_i;
                `YSYX210745_ALUOP_LBU : mem_addr_o = op1_i + imm_i;
                `YSYX210745_ALUOP_LHU : mem_addr_o = op1_i + imm_i;
                `YSYX210745_ALUOP_LWU : mem_addr_o = op1_i + imm_i;

                `YSYX210745_ALUOP_SB  : mem_addr_o = op1_i + imm_i;
                `YSYX210745_ALUOP_SH  : mem_addr_o = op1_i + imm_i;
                `YSYX210745_ALUOP_SW  : mem_addr_o = op1_i + imm_i; 
                `YSYX210745_ALUOP_SD  : mem_addr_o = op1_i + imm_i;

                default    : mem_addr_o = `YSYX210745_ZERO_WORD;
            endcase
        end
    end
   /* 
    always @ (*) begin
        if(rst == `YSYX210745_RST) 
            begin
                halt_ena_o = 1'b0; 
                skip_exe = 1'b0;                
            end
        else begin
            case(aluop_i)
                `YSYX210745_ALUOP_FALT  : begin 
                                    //$display("The program falt!"); 
                                    //$display("The a0 is %h. ", op1_i);
                                    halt_ena_o = 1'b1; 
                                    skip_exe = 1'b1;
                                end
                `YSYX210745_ALUOP_PUTCH : begin
                                    halt_ena_o = 1'b0; 
                                    skip_exe = 1'b1;
                                    //$write("%c",op1_i);
                                end 
                                
                default :
                    begin
                        halt_ena_o = 1'b0; 
                        skip_exe = 1'b0;                
                    end
            endcase
        end
    end
    */
    always @ (posedge clk) begin
        if(id_reg_valid_i)
            case(aluop_i)
                `YSYX210745_ALUOP_FALT  : begin 
                                    //$display("The program falt!"); 
                                    //$display("The a0 is %h. ", op1_i);
                                end
                `YSYX210745_ALUOP_PUTCH : begin
                                    //$write("%c",op1_i);
                                end                 
                default :;
            endcase
    end
// csr
    always @ (*) begin
        if(rst == `YSYX210745_RST) 
            begin
                csr_data_o  = `YSYX210745_ZERO_WORD;
            end
        else
            case(aluop_i)
                `YSYX210745_ALUOP_CSRRW : csr_data_o = op1_i;
                `YSYX210745_ALUOP_CSRRS : csr_data_o = op1_i | csr_data_i;
                `YSYX210745_ALUOP_CSRRC : csr_data_o = ~op1_i & csr_data_i;
                default      : csr_data_o  = `YSYX210745_ZERO_WORD;
            endcase
    end


endmodule


module ysyx_210745_exe_reg(

    input                     clk,
    input                     rst,
    input                     exe_stall_i,

    input  wire               exe_rd_w_ena_i,
    input  wire [`YSYX210745_REG_BUS]    exe_rd_w_addr_i,
    input  wire [`YSYX210745_REG_WIDTH]  exe_rd_w_data_i,  

    input  wire [5 : 0]       exe_aluop_i,
    input  wire [`YSYX210745_RAM_BUS]    exe_mem_addr_i,
    input  wire [`YSYX210745_REG_WIDTH]  exe_rs2_i,       
    //input  reg                exe_halt_ena_i,
    //input  wire               exe_skip_i, 


    output reg                exe_rd_w_ena_o,
    output reg  [`YSYX210745_REG_BUS]    exe_rd_w_addr_o,
    output reg  [`YSYX210745_REG_WIDTH]  exe_rd_w_data_o,  

    output reg  [5 : 0]       exe_aluop_o,
    output reg  [`YSYX210745_RAM_BUS]    exe_mem_addr_o,
    output reg  [`YSYX210745_REG_WIDTH]  exe_rs2_o       
    //output reg                exe_halt_ena_o,
    //output reg                exe_skip_o


);
    always@(posedge clk)begin
        if(rst == `YSYX210745_RST )begin
            exe_rd_w_ena_o  <= 0;
            exe_rd_w_addr_o <= 0;
            exe_rd_w_data_o <= 0;  
            exe_aluop_o     <= 0;
            exe_mem_addr_o  <= 0;
            exe_rs2_o       <= 0;       
            //exe_halt_ena_o  <= 0;
            //exe_skip_o      <= 0;
        end
        else if(exe_stall_i)begin
            exe_rd_w_ena_o  <= exe_rd_w_ena_o;
            exe_rd_w_addr_o <= exe_rd_w_addr_o;
            exe_rd_w_data_o   <= exe_rd_w_data_o;  
            exe_aluop_o     <= exe_aluop_o;
            exe_mem_addr_o  <= exe_mem_addr_o;
            exe_rs2_o       <= exe_rs2_o;       
            //exe_halt_ena_o  <= exe_halt_ena_o;
            //exe_skip_o      <= exe_skip_o;
        end
        else begin
            exe_rd_w_ena_o  <= exe_rd_w_ena_i;
            exe_rd_w_addr_o <= exe_rd_w_addr_i;
            exe_rd_w_data_o   <= exe_rd_w_data_i;  
            exe_aluop_o     <= exe_aluop_i;
            exe_mem_addr_o  <= exe_mem_addr_i;
            exe_rs2_o       <= exe_rs2_i;       
            //exe_halt_ena_o  <= exe_halt_ena_i;
            //exe_skip_o      <= exe_skip_i;
        end
    end





endmodule



module ysyx_210745_mem(
 
    input  wire               rst,

    input  wire               rd_w_ena_i,
    input  wire [`YSYX210745_REG_BUS]    rd_w_addr_i,
    input  wire [`YSYX210745_REG_WIDTH]  rd_w_data_i,
    
    input  wire [5:0]         aluop_i,
    input  wire [`YSYX210745_RAM_BUS]    mem_addr_i,
    input  wire [`YSYX210745_REG_WIDTH]  rs2_i, 
    //input  wire               halt_ena_i,
    //input  wire               skip_exe_i,

    //csr
    input  wire [`YSYX210745_REG_WIDTH]  mtime_i, 
    input  wire [`YSYX210745_REG_WIDTH]  mtimecmp_i, 
    //output wire               clint_rd_o,
    output wire               clint_wr_o,
    output wire               mtime_ena_o,
    output wire               mtimecmp_ena_o,         

    //axi  
    output wire               mem_read_req_o,   
    //output wire               mem_write_req_o,        
    output wire               mem_valid_o,
    input  wire               mem_ready_i,
    output wire [`YSYX210745_RAM_BUS]    mem_addr_o,
    output wire [1:0]         mem_size_o,
    input  wire [`YSYX210745_RAM_WIDTH]  mem_data_read_i,
    output wire [`YSYX210745_RAM_WIDTH]  mem_data_write_o, 
  
    //wb_stage    
    output reg                rd_w_ena_o,
    output reg [`YSYX210745_REG_BUS]     rd_w_addr_o,
    output reg [`YSYX210745_REG_WIDTH]   rd_w_data_o,
    //output wire               halt_ena_o,
    //output wire               skip_mem_o,
    output wire               mem_data_valid_o




    );
    
    wire load_inst;
    wire store_inst;
    wire clint_inst;
    //wire mem_hs;
    wire [`YSYX210745_RAM_WIDTH] mem_data_read;
    reg [1:0] mem_size;
    reg [`YSYX210745_RAM_BUS] mem_addr;
    reg [`YSYX210745_RAM_WIDTH] mem_data_write;

    assign load_inst = ((aluop_i == `YSYX210745_ALUOP_LB) || (aluop_i == `YSYX210745_ALUOP_LH) || (aluop_i == `YSYX210745_ALUOP_LW) || (aluop_i == `YSYX210745_ALUOP_LD)
            || (aluop_i == `YSYX210745_ALUOP_LBU) || (aluop_i == `YSYX210745_ALUOP_LHU) || (aluop_i == `YSYX210745_ALUOP_LWU)) ? 1'b1 : 1'b0;
    assign store_inst = ((aluop_i == `YSYX210745_ALUOP_SB) || (aluop_i == `YSYX210745_ALUOP_SH) || (aluop_i == `YSYX210745_ALUOP_SW) || (aluop_i == `YSYX210745_ALUOP_SD)) ? 1'b1 : 1'b0;
   //assign mem_hs = mem_valid_o && mem_ready_i;

    //assign halt_ena_o = halt_ena_i;
    //assign skip_mem_o = skip_exe_i;
    assign mem_data_valid_o = mem_valid_o & mem_ready_i;
    assign clint_inst = (mem_addr_i == `YSYX210745_MTIMECMP_ADDR | mem_addr_i == `YSYX210745_MTIME_ADDR);
    assign mtime_ena_o = mem_addr_i == `YSYX210745_MTIME_ADDR;
    assign mtimecmp_ena_o = mem_addr_i == `YSYX210745_MTIMECMP_ADDR;
    wire clint_rd_o = clint_inst & load_inst;
    assign clint_wr_o = clint_inst & store_inst;
    assign mem_data_read = ~clint_rd_o? mem_data_read_i:
                           (mem_addr_i == `YSYX210745_MTIMECMP_ADDR)? mtimecmp_i:
                           mtime_i;

    //axi
    assign mem_read_req_o   = load_inst;
    //assign mem_write_req_o  = store_inst;
    assign mem_valid_o      = (load_inst || store_inst) & ~clint_inst ;
    assign mem_addr_o       = mem_addr;
    assign mem_size_o       = mem_size;
    assign mem_data_write_o = mem_data_write;
    




    always @ (*) begin
        if(rst == `YSYX210745_RST) begin
            rd_w_ena_o     =  1'b0;
            rd_w_addr_o    =  `YSYX210745_REG_ADDR_0;
            rd_w_data_o    =  `YSYX210745_ZERO_WORD;
            mem_addr       =  `YSYX210745_ZERO_WORD;
            mem_data_write =  `YSYX210745_ZERO_WORD;
            mem_size       =  2'b0; 
        end
        else begin
            if(load_inst == 1'b1) begin
                rd_w_ena_o     = rd_w_ena_i;           
                rd_w_addr_o    = rd_w_addr_i;
                mem_data_write = `YSYX210745_ZERO_WORD;
                mem_addr       = mem_addr_i;
                case(aluop_i)
                    `YSYX210745_ALUOP_LB  : begin mem_size = `YSYX210745_SIZE_B; rd_w_data_o = {{ 56{mem_data_read[7]} },mem_data_read[7:0]};    end
                    `YSYX210745_ALUOP_LH  : begin mem_size = `YSYX210745_SIZE_H; rd_w_data_o = {{ 48{mem_data_read[15]} },mem_data_read[15:0]};  end
                    `YSYX210745_ALUOP_LW  : begin mem_size = `YSYX210745_SIZE_W; rd_w_data_o = {{ 32{mem_data_read[31]} },mem_data_read[31:0]};  end
                    `YSYX210745_ALUOP_LD  : begin mem_size = `YSYX210745_SIZE_D; rd_w_data_o = mem_data_read;                                      end
                    `YSYX210745_ALUOP_LBU : begin mem_size = `YSYX210745_SIZE_B; rd_w_data_o = {56'b0,mem_data_read[7:0]};                         end
                    `YSYX210745_ALUOP_LHU : begin mem_size = `YSYX210745_SIZE_H; rd_w_data_o = {48'b0,mem_data_read[15:0]};                        end
                    `YSYX210745_ALUOP_LWU : begin mem_size = `YSYX210745_SIZE_W; rd_w_data_o = {32'b0,mem_data_read[31:0]};                        end 
                    default    : begin mem_size =  2'b0;   rd_w_data_o = rd_w_data_i;                                          end                                          
                endcase
            end
            else if(store_inst == 1'b1)begin
                rd_w_ena_o   = 1'b0;
                rd_w_addr_o  = `YSYX210745_REG_ADDR_0;
                rd_w_data_o  = `YSYX210745_ZERO_WORD;
                mem_addr     = mem_addr_i;
                case(aluop_i)
                    `YSYX210745_ALUOP_SB : begin mem_size = `YSYX210745_SIZE_B; mem_data_write = { 56'b0, rs2_i[7:0] };  end
                    `YSYX210745_ALUOP_SH : begin mem_size = `YSYX210745_SIZE_H; mem_data_write = { 48'b0, rs2_i[15:0] }; end  
                    `YSYX210745_ALUOP_SW : begin mem_size = `YSYX210745_SIZE_W; mem_data_write = { 32'b0, rs2_i[31:0] }; end
                    `YSYX210745_ALUOP_SD : begin mem_size = `YSYX210745_SIZE_D; mem_data_write = rs2_i;                  end
                    default   : begin mem_size = 2'b0;    mem_data_write = `YSYX210745_ZERO_WORD;             end  
                endcase
            end
            else begin
                rd_w_ena_o     = rd_w_ena_i;
                rd_w_addr_o    = rd_w_addr_i;
                rd_w_data_o    = rd_w_data_i;
                mem_addr       = `YSYX210745_ZERO_WORD;
                mem_data_write = `YSYX210745_ZERO_WORD;
                mem_size       = 2'b0; 
            end
        end
    end
   
endmodule


module ysyx_210745_mem_reg(

    input  wire                clk,
    input  wire                rst,
    input  wire                mem_stall_i,      //~mem_ready

    //input  wire [`YSYX210745_RAM_BUS]     mem_pc_i,
    //input  wire [31:0]         mem_inst_i,
    input  wire                mem_rd_w_ena_i,
    input  wire [`YSYX210745_REG_BUS]     mem_rd_w_addr_i,
    input  wire [`YSYX210745_REG_WIDTH]   mem_rd_w_data_i,
    //input  wire                mem_halt_ena_i,
    //input  wire                mem_skip_i,

    //input  wire                mem_reg_valid_i,

    //input  wire [`YSYX210745_REG_WIDTH]   mem_mstatus_i,
    //input  wire [`YSYX210745_REG_WIDTH]   mem_mie_i,
    //input  wire [`YSYX210745_REG_WIDTH]   mem_mtvec_i,
    //input  wire [`YSYX210745_REG_WIDTH]   mem_mepc_i,
    //input  wire [`YSYX210745_REG_WIDTH]   mem_mcause_i,
    //input  wire [`YSYX210745_REG_WIDTH]   mem_mtval_i,
    //input  wire [`YSYX210745_REG_WIDTH]   mem_mip_i,
    //input  wire [`YSYX210745_REG_WIDTH]   mem_medeleg_i,
    //input  wire [`YSYX210745_REG_WIDTH]   mem_mideleg_i,
    //input  wire [`YSYX210745_REG_WIDTH]   mem_mscratch_i,

    //output reg  [`YSYX210745_RAM_BUS]     mem_pc_o,
    //output reg  [31:0]         mem_inst_o,
    output reg                 mem_rd_w_ena_o,
    output reg  [`YSYX210745_REG_BUS]     mem_rd_w_addr_o,
    output reg  [`YSYX210745_REG_WIDTH]   mem_rd_w_data_o
    //output reg                 mem_halt_ena_o,
    //output reg                 mem_skip_o,
    
    //output reg                 mem_reg_valid_o,

    //output reg  [`YSYX210745_REG_WIDTH]   mem_mstatus_o,
    //output reg  [`YSYX210745_REG_WIDTH]   mem_mie_o,
    //output reg  [`YSYX210745_REG_WIDTH]   mem_mtvec_o,
    //output reg  [`YSYX210745_REG_WIDTH]   mem_mepc_o,
    //output reg  [`YSYX210745_REG_WIDTH]   mem_mcause_o,
    //output reg  [`YSYX210745_REG_WIDTH]   mem_mtval_o,
    //output reg  [`YSYX210745_REG_WIDTH]   mem_mip_o,
    //output reg  [`YSYX210745_REG_WIDTH]   mem_medeleg_o,
    //output reg  [`YSYX210745_REG_WIDTH]   mem_mideleg_o,
    //output reg  [`YSYX210745_REG_WIDTH]   mem_mscratch_o

);

    always@(posedge clk)begin
        if(rst == `YSYX210745_RST )begin
            mem_rd_w_ena_o  <= 0;
            mem_rd_w_addr_o <= 0;
            mem_rd_w_data_o <= 0;         
        end
        else if(mem_stall_i)begin
            mem_rd_w_ena_o  <= mem_rd_w_ena_o;
            mem_rd_w_addr_o <= mem_rd_w_addr_o;
            mem_rd_w_data_o <= mem_rd_w_data_o;         
        end
        else begin
            mem_rd_w_ena_o  <= mem_rd_w_ena_i;
            mem_rd_w_addr_o <= mem_rd_w_addr_i;
            mem_rd_w_data_o <= mem_rd_w_data_i;         
        end
    end
/*
        always@(posedge clk)begin
        if(rst == `YSYX210745_RST )begin
            mem_mstatus_o  <= 0;
            mem_mie_o      <= 0;
            mem_mtvec_o    <= 0;
            mem_mepc_o     <= 0;
            mem_mcause_o   <= 0;
            mem_mtval_o    <= 0;
            mem_mip_o      <= 0;
            mem_medeleg_o  <= 0;
            mem_mideleg_o  <= 0;
            mem_mscratch_o <= 0;
        end
        else if(mem_stall_i)begin
            mem_mstatus_o  <=  mem_mstatus_o ;
            mem_mie_o      <=  mem_mie_o     ;
            mem_mtvec_o    <=  mem_mtvec_o   ;
            mem_mepc_o     <=  mem_mepc_o    ;
            mem_mcause_o   <=  mem_mcause_o  ;
            mem_mtval_o    <=  mem_mtval_o   ;
            mem_mip_o      <=  mem_mip_o     ;
            mem_medeleg_o  <=  mem_medeleg_o ;
            mem_mideleg_o  <=  mem_mideleg_o ;
            mem_mscratch_o <=  mem_mscratch_o;
        end
        else begin
            mem_mstatus_o  <=  mem_mstatus_i ;
            mem_mie_o      <=  mem_mie_i     ;
            mem_mtvec_o    <=  mem_mtvec_i   ;
            mem_mepc_o     <=  mem_mepc_i    ;
            mem_mcause_o   <=  mem_mcause_i  ;
            mem_mtval_o    <=  mem_mtval_i   ;
            mem_mip_o      <=  mem_mip_i     ;
            mem_medeleg_o  <=  mem_medeleg_i ;
            mem_mideleg_o  <=  mem_mideleg_i ;
            mem_mscratch_o <=  mem_mscratch_i;
        end
    end
*/


endmodule

/*
module ysyx_210745_wb(

    input                       rd_w_ena_i,
    input       [`YSYX210745_REG_BUS]      rd_w_addr_i,
    input       [`YSYX210745_REG_WIDTH]    rd_w_data_i,
    input                       wb_halt_ena_i,
    input                       wb_skip_i,

    output wire                 rd_w_ena_o,
    output wire [`YSYX210745_REG_BUS]      rd_w_addr_o,
    output wire [`YSYX210745_REG_WIDTH]    rd_w_data_o,
    output wire                 wb_halt_ena_o,
    output wire                 wb_skip_o

);

    assign rd_w_ena_o    = rd_w_ena_i;
    assign rd_w_addr_o   = rd_w_addr_i;
    assign rd_w_data_o   = rd_w_data_i;
    assign wb_halt_ena_o = wb_halt_ena_i;
    assign wb_skip_o     = wb_skip_i;

endmodule
*/
/*
module ysyx_210745_wb_reg(

    //  这一级主要是为指令提交设计，没有实际意义
    input wire               clk,
    input wire               rst,
    input wire               wb_stall_i,

    input  wire [`YSYX210745_RAM_BUS]   wb_pc_i,
    input  wire [31:0]       wb_inst_i,
    input  wire              wb_rd_w_ena_i,
    input  wire [`YSYX210745_REG_BUS]   wb_rd_w_addr_i,
    input  wire [`YSYX210745_REG_WIDTH] wb_rd_w_data_i,
    input  wire              wb_halt_ena_i,
    input  wire              wb_skip_i,

    input  wire              wb_reg_valid_i,

    input  wire [`YSYX210745_REG_WIDTH] wb_mstatus_i,
    input  wire [`YSYX210745_REG_WIDTH] wb_mie_i,
    input  wire [`YSYX210745_REG_WIDTH] wb_mtvec_i,
    input  wire [`YSYX210745_REG_WIDTH] wb_mepc_i,
    input  wire [`YSYX210745_REG_WIDTH] wb_mcause_i,
    input  wire [`YSYX210745_REG_WIDTH] wb_mtval_i,
    input  wire [`YSYX210745_REG_WIDTH] wb_mip_i,
    input  wire [`YSYX210745_REG_WIDTH] wb_medeleg_i,
    input  wire [`YSYX210745_REG_WIDTH] wb_mideleg_i,
    input  wire [`YSYX210745_REG_WIDTH] wb_mscratch_i,

    output reg  [`YSYX210745_RAM_BUS]   wb_pc_o,
    output reg  [31:0]       wb_inst_o,
    output reg               wb_rd_w_ena_o,
    output reg  [`YSYX210745_REG_BUS]   wb_rd_w_addr_o,
    output reg  [`YSYX210745_REG_WIDTH] wb_rd_w_data_o,
    output reg               wb_halt_ena_o,
    output reg               wb_skip_o,

    output reg               wb_reg_valid_o,

    output reg  [`YSYX210745_REG_WIDTH] wb_mstatus_o,
    output reg  [`YSYX210745_REG_WIDTH] wb_mie_o,
    output reg  [`YSYX210745_REG_WIDTH] wb_mtvec_o,
    output reg  [`YSYX210745_REG_WIDTH] wb_mepc_o,
    output reg  [`YSYX210745_REG_WIDTH] wb_mcause_o,
    output reg  [`YSYX210745_REG_WIDTH] wb_mtval_o,
    output reg  [`YSYX210745_REG_WIDTH] wb_mip_o,
    output reg  [`YSYX210745_REG_WIDTH] wb_medeleg_o,
    output reg  [`YSYX210745_REG_WIDTH] wb_mideleg_o,
    output reg  [`YSYX210745_REG_WIDTH] wb_mscratch_o


);


    always@(posedge clk)begin
        if(rst == `YSYX210745_RST )begin
            wb_pc_o        <= 0;
            wb_inst_o      <= 0;
            wb_rd_w_ena_o  <= 0;
            wb_rd_w_addr_o <= 0;         
            wb_rd_w_data_o <= 0;
            wb_halt_ena_o  <= 0;
            wb_skip_o      <= 0;
            wb_reg_valid_o <= 0;
        end
        else if(wb_stall_i)begin
            wb_pc_o        <= wb_pc_o;
            wb_inst_o      <= wb_inst_o;
            wb_rd_w_ena_o  <= wb_rd_w_ena_o;
            wb_rd_w_addr_o <= wb_rd_w_addr_o;         
            wb_rd_w_data_o    <= wb_rd_w_data_o;
            wb_halt_ena_o  <= wb_halt_ena_o;
            wb_skip_o      <= wb_skip_o;
            wb_reg_valid_o <= wb_reg_valid_o;
        end
        else begin
            wb_pc_o        <= wb_pc_i;
            wb_inst_o      <= wb_inst_i;
            wb_rd_w_ena_o  <= wb_rd_w_ena_i;
            wb_rd_w_addr_o <= wb_rd_w_addr_i;         
            wb_rd_w_data_o    <= wb_rd_w_data_i;
            wb_halt_ena_o  <= wb_halt_ena_i;
            wb_skip_o      <= wb_skip_i;
            wb_reg_valid_o <= wb_reg_valid_i;
        end
    end

    always@(posedge clk)begin
        if(rst == `YSYX210745_RST )begin
            wb_mstatus_o  <= 0;
            wb_mie_o      <= 0;
            wb_mtvec_o    <= 0;
            wb_mepc_o     <= 0;
            wb_mcause_o   <= 0;
            wb_mtval_o    <= 0;
            wb_mip_o      <= 0;
            wb_medeleg_o  <= 0;
            wb_mideleg_o  <= 0;
            wb_mscratch_o <= 0;
        end
        else if(wb_stall_i)begin
            wb_mstatus_o  <=  wb_mstatus_o ;
            wb_mie_o      <=  wb_mie_o     ;
            wb_mtvec_o    <=  wb_mtvec_o   ;
            wb_mepc_o     <=  wb_mepc_o    ;
            wb_mcause_o   <=  wb_mcause_o  ;
            wb_mtval_o    <=  wb_mtval_o   ;
            wb_mip_o      <=  wb_mip_o     ;
            wb_medeleg_o  <=  wb_medeleg_o ;
            wb_mideleg_o  <=  wb_mideleg_o ;
            wb_mscratch_o <=  wb_mscratch_o;
        end
        else begin
            wb_mstatus_o  <=  wb_mstatus_i ;
            wb_mie_o      <=  wb_mie_i     ;
            wb_mtvec_o    <=  wb_mtvec_i   ;
            wb_mepc_o     <=  wb_mepc_i    ;
            wb_mcause_o   <=  wb_mcause_i  ;
            wb_mtval_o    <=  wb_mtval_i   ;
            wb_mip_o      <=  wb_mip_i     ;
            wb_medeleg_o  <=  wb_medeleg_i ;
            wb_mideleg_o  <=  wb_mideleg_i ;
            wb_mscratch_o <=  wb_mscratch_i;
        end
    end




endmodule
*/


module ysyx_210745_arbiter(

    input wire            clock,    
    input wire            reset,
    //pc
    //input  wire           if_read_req_i,
    input  wire           if_valid_i,
    output reg            if_ready_o,
    output wire [63:0]    if_data_read_o,
    input  wire [63:0]    if_addr_i,
    input  wire [1 :0]    if_size,

    //mem
    input  wire           mem_read_req_i,
    //input  wire           mem_write_req_i,
    input  wire           mem_valid_i,
    output wire           mem_ready_o,
    input  wire [63:0]    mem_addr_i,
    input  wire [1 :0]    mem_size_i,
    output wire [63:0]    mem_data_read_o,
    input  wire [63:0]    mem_data_write_i,

    //axi   
	output reg            rw_valid_o,
	input  wire           rw_ready_i,
    output wire           rw_req_o,
    input  wire [63:0]    data_read_i,
    output wire [63:0]    data_write_o,
    output wire [63:0]    rw_addr_o,
    output wire [1 :0]    rw_size_o

);
    reg [0:0] arbiter_state;

    /*
    //arbiter state machine
    parameter [1:0] ARBITER_IDLE = 2'b00;
    parameter [1:0] ARBITER_IF   = 2'b01;
    parameter [1:0] ARBITER_MEM  = 2'b10;
    //parameter [1:0] ARBITER_WAIT = 2'b11;

    always @(posedge clock) 
        begin
            if (reset) 
                arbiter_state <= ARBITER_IDLE;
            else
                begin
                    case(arbiter_state)
                        ARBITER_IDLE:
                            begin
                                if(mem_valid_i)
                                    arbiter_state <= ARBITER_MEM;  
                                else if(if_valid_i)
                                    arbiter_state <= ARBITER_IF;
                                else
                                    arbiter_state <= arbiter_state;  
                            end
                        ARBITER_IF:
                            begin
                                if(trans_done_i)
                                    arbiter_state <= ARBITER_IDLE;
                                else
                                    arbiter_state <= arbiter_state;     
                            end
                        ARBITER_MEM:
                            begin
                                if(trans_done_i)
                                    arbiter_state <= ARBITER_IDLE;
                                else
                                    arbiter_state <= arbiter_state; 
                            end
                        default:
                            arbiter_state <= arbiter_state;
                    endcase
                end
        end
    */
        //arbiter state machin
    parameter [0:0] ARBITER_IF   = 1'b0;
    parameter [0:0] ARBITER_MEM  = 1'b1;

    always @(posedge clock) 
        begin
            if (reset == `YSYX210745_RST) 
                arbiter_state <= ARBITER_IF;
            else
                begin
                    case(arbiter_state)
                        ARBITER_IF:
                            begin
                                if(if_ready_o && mem_valid_i)
                                    arbiter_state <= ARBITER_MEM;
                                else
                                    arbiter_state <= arbiter_state;     
                            end
                        ARBITER_MEM:
                            begin
                                if(mem_ready_o && if_valid_i)
                                    arbiter_state <= ARBITER_IF;
                                else
                                    arbiter_state <= arbiter_state; 
                            end
                        default:
                            arbiter_state <= arbiter_state;
                    endcase
                end
        end

    //axi
    always@(*)
    begin
        if (reset == `YSYX210745_RST) 
            begin
                if_ready_o      = 1'b0;
                if_data_read_o  = 64'b0;
                mem_ready_o     = 1'b0;
                mem_data_read_o = 64'b0;
                rw_valid_o      = 1'b0;
                rw_req_o        = 1'b0;
                data_write_o    = 64'b0;
                rw_addr_o       = 64'b0;
                rw_size_o       = 2'b0;
            end
        else if(arbiter_state == ARBITER_IF)
            begin
                if_ready_o      = rw_ready_i;
                if_data_read_o  = data_read_i;
                mem_ready_o     = 1'b0;
                mem_data_read_o = 64'b0;
                rw_valid_o      = if_valid_i;
                rw_req_o        = `YSYX210745_REQ_READ;
                data_write_o    = 64'b0;
                rw_addr_o       = if_addr_i;
                rw_size_o       = if_size;
            end
        else if(arbiter_state == ARBITER_MEM)
            begin
                if_ready_o      = 1'b0;
                if_data_read_o  = 64'b0;
                mem_ready_o     = rw_ready_i;
                mem_data_read_o = data_read_i;
                rw_valid_o      = mem_valid_i;
                rw_req_o        = mem_read_req_i ? `YSYX210745_REQ_READ : `YSYX210745_REQ_WRITE;
                data_write_o    = mem_data_write_i;
                rw_addr_o       = mem_addr_i;
                rw_size_o       = mem_size_i; 
            end
        else
            begin
                if_ready_o      = 1'b0;
                if_data_read_o  = 64'b0;
                mem_ready_o     = 1'b0;
                mem_data_read_o = 64'b0;
                rw_valid_o      = 1'b0;
                rw_req_o        = 1'b0;
                data_write_o    = 64'b0;
                rw_addr_o       = 64'b0;
                rw_size_o       = 2'b0;
            end  
    end


endmodule




module ysyx_210745_axi_rw # (
    parameter RW_DATA_WIDTH     = 64,
    //parameter RW_ADDR_WIDTH     = 64,
    parameter YSYX210745_AXI_DATA_WIDTH    = 64,
    //parameter YSYX210745_AXI_ADDR_WIDTH    = 64,
    parameter YSYX210745_AXI_ID_WIDTH      = 4
    //parameter YSYX210745_AXI_USER_WIDTH    = 1
)(
    input                               clock,
    input                               reset,

	input                               rw_valid_i,
	output                              rw_ready_o,
    input                               rw_req_i,
    output wire [RW_DATA_WIDTH-1:0]     data_read_o,
    input  [RW_DATA_WIDTH-1:0]          data_write_i,
    input  [YSYX210745_AXI_DATA_WIDTH-1:0]         rw_addr_i,
    input  [1:0]                        rw_size_i,
    //output [1:0]                        rw_resp_o,
    //output                              trans_done_o,

    // Advanced eXtensible Interface
    input                               axi_aw_ready_i,
    output                              axi_aw_valid_o,
    output [31:0]                       axi_aw_addr_o,
    //output [2:0]                        axi_aw_prot_o,
    output [YSYX210745_AXI_ID_WIDTH-1:0]           axi_aw_id_o,
    //output [YSYX210745_AXI_USER_WIDTH-1:0]         axi_aw_user_o,
    output [7:0]                        axi_aw_len_o,
    output [2:0]                        axi_aw_size_o,
    output [1:0]                        axi_aw_burst_o,
    //output                              axi_aw_lock_o,
    //output [3:0]                        axi_aw_cache_o,
    //output [3:0]                        axi_aw_qos_o,
    //output [3:0]                        axi_aw_region_o,

    input                               axi_w_ready_i,
    output                              axi_w_valid_o,
    output [YSYX210745_AXI_DATA_WIDTH-1:0]         axi_w_data_o,
    output [YSYX210745_AXI_DATA_WIDTH/8-1:0]       axi_w_strb_o,
    output                              axi_w_last_o,
    //output [YSYX210745_AXI_USER_WIDTH-1:0]         axi_w_user_o,
    
    output                              axi_b_ready_o,
    input                               axi_b_valid_i,
    //input  [1:0]                        axi_b_resp_i,
    //input  [YSYX210745_AXI_ID_WIDTH-1:0]           axi_b_id_i,
    //input  [YSYX210745_AXI_USER_WIDTH-1:0]         axi_b_user_i,

    input                               axi_ar_ready_i,
    output                              axi_ar_valid_o,
    output [31:0]                       axi_ar_addr_o,
    //output [2:0]                        axi_ar_prot_o,
    output [YSYX210745_AXI_ID_WIDTH-1:0]           axi_ar_id_o,
    //output [YSYX210745_AXI_USER_WIDTH-1:0]         axi_ar_user_o,
    output [7:0]                        axi_ar_len_o,
    output [2:0]                        axi_ar_size_o,
    output [1:0]                        axi_ar_burst_o,
    //output                              axi_ar_lock_o,
    //output [3:0]                        axi_ar_cache_o,
    //output [3:0]                        axi_ar_qos_o,
    //output [3:0]                        axi_ar_region_o,
    
    output                              axi_r_ready_o,
    input                               axi_r_valid_i,
    //input  [1:0]                        axi_r_resp_i,
    input  [YSYX210745_AXI_DATA_WIDTH-1:0]         axi_r_data_i,
    input                               axi_r_last_i
    //input  [YSYX210745_AXI_ID_WIDTH-1:0]           axi_r_id_i
    //input  [YSYX210745_AXI_USER_WIDTH-1:0]         axi_r_user_i
);
//soc

    wire [2:0] axi_size  =  size_b ? 3'b00 :
                            size_h ? 3'b01 :
                            size_w ? 3'b10 :
                            size_d ? 3'b11 : 3'b11;

    reg  [RW_DATA_WIDTH-1:0]      data_read;
    //wire [RW_DATA_WIDTH-1:0]      data_read_tmp;
    //reg  [RW_DATA_WIDTH-1:0]      data_read_bufer;
    //reg  [RW_DATA_WIDTH-1:0]      data_write_bufer;
    //wire soc_rw = rw_addr_i < 64'h80000000;
    //assign data_read_tmp = soc_rw ? data_read_bufer : data_read;
    /*
    assign data_read_o = !soc_rw ? data_read :
                          size_b ? {56'b0, data_read_bufer[7:0]} :
                          size_h ? {48'b0, data_read_bufer[15:0]} :
                          size_w ? {32'b0, data_read_bufer[31:0]} : data_read_bufer ;//不会出现对外设的超过4字节的访问
    */
    assign data_read_o = data_read;                     
     

    wire w_trans    = rw_req_i == `YSYX210745_REQ_WRITE;
    wire r_trans    = rw_req_i == `YSYX210745_REQ_READ;
    wire w_valid    = rw_valid_i & w_trans;
    wire r_valid    = rw_valid_i & r_trans;

    // handshake
    wire aw_hs      = axi_aw_ready_i & axi_aw_valid_o;
    wire w_hs       = axi_w_ready_i  & axi_w_valid_o;
    wire b_hs       = axi_b_ready_o  & axi_b_valid_i;
    wire ar_hs      = axi_ar_ready_i & axi_ar_valid_o;
    wire r_hs       = axi_r_ready_o  & axi_r_valid_i;

    wire w_done     = w_hs & axi_w_last_o;
    wire r_done     = r_hs & axi_r_last_i;

    wire trans_done_o = w_trans ? b_hs : r_done;

    
    // ------------------State Machine------------------
    parameter [1:0] W_STATE_IDLE = 2'b00, W_STATE_ADDR = 2'b01, W_STATE_WRITE = 2'b10, W_STATE_RESP = 2'b11;
    parameter [1:0] R_STATE_IDLE = 2'b00, R_STATE_ADDR = 2'b01, R_STATE_READ  = 2'b10, R_STATE_WAIT = 2'b11;

    reg [1:0] w_state, r_state;
    wire w_state_idle = w_state == W_STATE_IDLE, w_state_addr = w_state == W_STATE_ADDR, w_state_write = w_state == W_STATE_WRITE, w_state_resp = w_state == W_STATE_RESP;
    wire r_state_idle = r_state == R_STATE_IDLE, r_state_addr = r_state == R_STATE_ADDR, r_state_read  = r_state == R_STATE_READ;

    // Wirte State Machine
    always @(posedge clock) begin
        if (reset) begin
            w_state <= W_STATE_IDLE;
        end
        else begin
            if (w_valid) begin
                case (w_state)
                    W_STATE_IDLE:               w_state <= W_STATE_ADDR;
                    W_STATE_ADDR:  if (aw_hs)   w_state <= W_STATE_WRITE;
                    W_STATE_WRITE: if (w_done)  w_state <= W_STATE_RESP;
                    W_STATE_RESP:  if (b_hs)    w_state <= W_STATE_IDLE;
                endcase
            end
        end
    end

    // Read State Machine
    always @(posedge clock) begin
        if (reset) begin
            r_state <= R_STATE_IDLE;
        end
        else begin
            if (r_valid) begin
                case (r_state)
                    R_STATE_IDLE:               r_state <= R_STATE_ADDR;
                    R_STATE_ADDR: if (ar_hs)    r_state <= R_STATE_READ;
                    R_STATE_READ: if (r_done)   r_state <= R_STATE_WAIT;
                    R_STATE_WAIT:               r_state <= R_STATE_IDLE;
                endcase
            end
        end
    end


    // ------------------Number of transmission------------------
    reg [7:0] len;
    wire len_reset      = reset | (w_trans & w_state_idle) | (r_trans & r_state_idle);
    wire len_incr_en    = (len != axi_len) & (w_hs | r_hs);
    always @(posedge clock) begin
        if (len_reset) begin
            len <= 0;
        end
        else if (len_incr_en) begin
            len <= len + 1;
        end
    end


    // ------------------Process Data------------------
    parameter ALIGNED_WIDTH = $clog2(YSYX210745_AXI_DATA_WIDTH / 8);
    parameter OFFSET_WIDTH  = $clog2(YSYX210745_AXI_DATA_WIDTH);
    //parameter AXI_SIZE      = $clog2(YSYX210745_AXI_DATA_WIDTH / 8);
    parameter MASK_WIDTH    = YSYX210745_AXI_DATA_WIDTH * 2;
    parameter TRANS_LEN     = RW_DATA_WIDTH / YSYX210745_AXI_DATA_WIDTH;
    parameter BLOCK_TRANS   = TRANS_LEN > 1 ? 1'b1 : 1'b0;
    parameter STRB_WIDTH    = YSYX210745_AXI_DATA_WIDTH /8;

    wire aligned            = BLOCK_TRANS | rw_addr_i[ALIGNED_WIDTH-1:0] == 0;
    wire size_b             = rw_size_i == `YSYX210745_SIZE_B;
    wire size_h             = rw_size_i == `YSYX210745_SIZE_H;
    wire size_w             = rw_size_i == `YSYX210745_SIZE_W;
    wire size_d             = rw_size_i == `YSYX210745_SIZE_D;
    wire [3:0] addr_op1     = {{4-ALIGNED_WIDTH{1'b0}}, rw_addr_i[ALIGNED_WIDTH-1:0]};
    wire [3:0] addr_op2     = ({4{size_b}} & {4'b0})
                                | ({4{size_h}} & {4'b1})
                                | ({4{size_w}} & {4'b11})
                                | ({4{size_d}} & {4'b111})
                                ;
    wire [3:0] addr_end     = addr_op1 + addr_op2;
    wire overstep           = addr_end[3:ALIGNED_WIDTH] != 0;

    wire [7:0] axi_len      = aligned ? TRANS_LEN - 1 : {{7{1'b0}}, overstep};//

    
    //wire [YSYX210745_AXI_ADDR_WIDTH-1:0] axi_addr          = {rw_addr_i[YSYX210745_AXI_ADDR_WIDTH-1:ALIGNED_WIDTH], {ALIGNED_WIDTH{1'b0}}};
    wire [OFFSET_WIDTH-1:0] aligned_offset_l    = {{OFFSET_WIDTH-ALIGNED_WIDTH{1'b0}}, {rw_addr_i[ALIGNED_WIDTH-1:0]}} << 3;
    wire [OFFSET_WIDTH  :0] aligned_offset_h_tmp= YSYX210745_AXI_DATA_WIDTH - aligned_offset_l;
    wire [OFFSET_WIDTH-1:0] aligned_offset_h    = aligned_offset_h_tmp[5:0];
    wire [MASK_WIDTH-1:0] mask                  = (({MASK_WIDTH{size_b}} & {{MASK_WIDTH-8{1'b0}}, 8'hff})
                                                    | ({MASK_WIDTH{size_h}} & {{MASK_WIDTH-16{1'b0}}, 16'hffff})
                                                    | ({MASK_WIDTH{size_w}} & {{MASK_WIDTH-32{1'b0}}, 32'hffffffff})
                                                    | ({MASK_WIDTH{size_d}} & {{MASK_WIDTH-64{1'b0}}, 64'hffffffff_ffffffff})
                                                    ) << aligned_offset_l;
    wire [YSYX210745_AXI_DATA_WIDTH-1:0] mask_l            = mask[YSYX210745_AXI_DATA_WIDTH-1:0];
    wire [YSYX210745_AXI_DATA_WIDTH-1:0] mask_h            = mask[MASK_WIDTH-1:YSYX210745_AXI_DATA_WIDTH];

    wire [YSYX210745_AXI_ID_WIDTH-1:0] axi_id              = {YSYX210745_AXI_ID_WIDTH{1'b0}};
    //wire [YSYX210745_AXI_USER_WIDTH-1:0] axi_user          = {YSYX210745_AXI_USER_WIDTH{1'b0}};
 
    reg rw_ready;
    wire rw_ready_nxt = trans_done_o;
    wire rw_ready_en      = trans_done_o | rw_ready;
    always @(posedge clock) begin
        if (reset) begin
            rw_ready <= 0;
        end
        else if (rw_ready_en) begin
            rw_ready <= rw_ready_nxt;
        end
    end
    
    assign rw_ready_o     = rw_ready;

/*
    reg [1:0] rw_resp;
    wire [1:0] rw_resp_nxt = w_trans ? axi_b_resp_i : axi_r_resp_i;
    wire resp_en = trans_done_o;
    always @(posedge clock) begin
        if (reset) begin
            rw_resp <= 0;
        end
        else if (resp_en) begin
            rw_resp <= rw_resp_nxt;
        end
    end
    //assign rw_resp_o      = rw_resp;
*/

    // ------------------Write Transaction------------------

    //Write address channel signals
    assign axi_aw_valid_o   = w_state_addr && w_valid;
    assign axi_aw_addr_o    = rw_addr_i[31:0];//soc_rw ? rw_addr_i : axi_addr;
    //assign axi_aw_prot_o    = `YSYX210745_AXI_PROT_UNPRIVILEGED_ACCESS | `YSYX210745_AXI_PROT_SECURE_ACCESS | `YSYX210745_AXI_PROT_DATA_ACCESS;
    assign axi_aw_id_o      = axi_id;
    //assign axi_aw_user_o    = axi_user;
    assign axi_aw_len_o     = axi_len;
    assign axi_aw_size_o    = axi_size;
    assign axi_aw_burst_o   = `YSYX210745_AXI_BURST_TYPE_INCR;
    //assign axi_aw_lock_o    = 1'b0;
    //assign axi_aw_cache_o   = `YSYX210745_AXI_AWCACHE_NORMAL_NON_CACHEABLE_NON_BUFFERABLE;
    //assign axi_aw_qos_o     = 4'h0;

    //Write data channel signals

    assign axi_w_valid_o    = w_state_write;
    /*
    assign axi_w_data_o     = ~soc_rw ? axi_w_data :
                                size_b ? {56'b0,data_write_i[7:0]} :
                                size_h ? {48'b0,data_write_i[15:0]} :
                                size_w ? {32'b0,data_write_i[31:0]} : data_write_i;
    assign axi_w_strb_o     = ~soc_rw ? axi_w_strb :  //写操作的话对于外设就不考虑非对齐传输了
                                size_b ? 8'b1 :
                                size_h ? 8'b11 :
                                size_w ? 8'b1111 : 8'b11111111;
    */  
    assign axi_w_data_o     = axi_w_data ;
    assign axi_w_strb_o     = axi_w_strb ; 
    //wire strb_error =  axi_w_strb_o == 0;
            
    assign axi_w_last_o     = axi_w_last;
    //assign axi_w_user_o     = axi_user;

    //Write response channel signals

    assign axi_b_ready_o    = w_state_resp;

    reg  [YSYX210745_AXI_DATA_WIDTH-1:0]                   axi_w_data;
    reg  [YSYX210745_AXI_DATA_WIDTH/8-1:0]                 axi_w_strb;
    reg                                         axi_w_last;
    wire [RW_DATA_WIDTH+YSYX210745_AXI_DATA_WIDTH-1:0]     data_write_extend;//拓宽axi_data_width位，便于移位
    wire [STRB_WIDTH*2-1:0]                     write_strb;
    wire [YSYX210745_AXI_DATA_WIDTH/8-1:0]                     write_strb_l;
    wire [YSYX210745_AXI_DATA_WIDTH/8-1:0]                     write_strb_h;

    wire [YSYX210745_AXI_DATA_WIDTH-1:0] axi_w_data_l = data_write_extend[YSYX210745_AXI_DATA_WIDTH*2-1:YSYX210745_AXI_DATA_WIDTH];
    wire [YSYX210745_AXI_DATA_WIDTH-1:0] axi_w_data_h = data_write_extend[YSYX210745_AXI_DATA_WIDTH-1:0];

    assign data_write_extend   = {64'b0,data_write_i} << aligned_offset_l;
    //strb参考mask部分设计

    assign write_strb   = (({STRB_WIDTH*2{size_b}} & {{STRB_WIDTH*2-1{1'b0}}, 1'b1})
                         | ({STRB_WIDTH*2{size_h}} & {{STRB_WIDTH*2-2{1'b0}}, 2'b11})
                         | ({STRB_WIDTH*2{size_w}} & {{STRB_WIDTH*2-4{1'b0}}, 4'b1111})
                         | ({STRB_WIDTH*2{size_d}} & {{STRB_WIDTH*2-8{1'b0}}, 8'b1111_1111})
                         ) << rw_addr_i[ALIGNED_WIDTH-1:0];

    assign write_strb_l = write_strb[STRB_WIDTH-1:0];
    assign write_strb_h = write_strb[STRB_WIDTH*2-1:STRB_WIDTH];

    always@(*)
    begin
        if (reset) begin
            axi_w_strb = 0;
        end
        else if (~aligned & overstep & aw_hs) begin   //这里的和下面一样，也不支持非对齐的burst传输
                if (len[0]) begin
                    axi_w_strb = write_strb_h;
                end
                else begin
                    axi_w_strb = write_strb_l;
                end
            end
        else 
                axi_w_strb = write_strb_l;       
    end
    generate
        for (genvar i = 0; i < TRANS_LEN; i += 1) begin
            always @(posedge clock) begin
                if (reset) begin
                    axi_w_data <= 0;
                    //data_write_bufer <= 0;
                end
                else if (aw_hs) begin
                    axi_w_last <= (len == TRANS_LEN - 1);
                    //data_write_bufer <= data_write_i;
                    if (~aligned & overstep) begin   //这里的和下面一样，也不支持非对齐的burst传输
                        if (len[0]) begin
                            axi_w_data <= axi_w_data_h;
                            //axi_w_strb <= write_strb_h;
                        end
                        else begin
                            axi_w_data <= axi_w_data_l;
                            //axi_w_strb <= write_strb_l;
                        end
                    end
                    else if (len == i) begin
                        axi_w_data <= data_write_extend[i*YSYX210745_AXI_DATA_WIDTH+:YSYX210745_AXI_DATA_WIDTH];
                        //axi_w_strb <= write_strb_l;
                    end
                end
            end
        end
    endgenerate

    
    // ------------------Read Transaction------------------

    // Read address channel signals
    assign axi_ar_valid_o   = r_state_addr;
    assign axi_ar_addr_o    = rw_addr_i[31:0];//soc_rw ? rw_addr_i : axi_addr;
    //assign axi_ar_prot_o    = `YSYX210745_AXI_PROT_UNPRIVILEGED_ACCESS | `YSYX210745_AXI_PROT_SECURE_ACCESS | `YSYX210745_AXI_PROT_DATA_ACCESS;
    assign axi_ar_id_o      = axi_id;
    //assign axi_ar_user_o    = axi_user;
    assign axi_ar_len_o     = axi_len;
    assign axi_ar_size_o    = axi_size;
    assign axi_ar_burst_o   = `YSYX210745_AXI_BURST_TYPE_INCR;
    //assign axi_ar_lock_o    = 1'b0;
    //assign axi_ar_cache_o   = `YSYX210745_AXI_ARCACHE_NORMAL_NON_CACHEABLE_NON_BUFFERABLE;
    //assign axi_ar_qos_o     = 4'h0;

    // Read data channel signals
    assign axi_r_ready_o    = r_state_read;

    wire [YSYX210745_AXI_DATA_WIDTH-1:0] axi_r_data_l  = (axi_r_data_i & mask_l) >> aligned_offset_l;
    wire [YSYX210745_AXI_DATA_WIDTH-1:0] axi_r_data_h  = (axi_r_data_i & mask_h) << aligned_offset_h;

    generate
        for (genvar i = 0; i < TRANS_LEN; i += 1) begin
            always @(posedge clock) begin
                if (reset) begin
                    data_read[i*YSYX210745_AXI_DATA_WIDTH+:YSYX210745_AXI_DATA_WIDTH] <= 0;
                    //data_read_bufer <= 0;
                end
                else if (axi_r_ready_o & axi_r_valid_i) begin
                        //data_read_bufer <= axi_r_data_i;
                    if (~aligned & overstep) begin   //该部分应该是只考虑了非burst传输下的非对齐传输
                        if (len[0]) begin
                            data_read[YSYX210745_AXI_DATA_WIDTH-1:0] <= data_read[YSYX210745_AXI_DATA_WIDTH-1:0] | axi_r_data_h;
                        end
                        else begin
                            data_read[YSYX210745_AXI_DATA_WIDTH-1:0] <= axi_r_data_l;
                        end
                    end
                    else if (len == i) begin
                        data_read[i*YSYX210745_AXI_DATA_WIDTH+:YSYX210745_AXI_DATA_WIDTH] <= axi_r_data_l;
                    end
                end
            end
        end
    endgenerate

endmodule


module ysyx_210745_clint(

    input                   clk,
    input                   rst,

    //input                   clint_rd_i,
    input                   clint_wr_i,
    input                   mtime_ena_i,
    input                   mtimecmp_ena_i,
    input      [`YSYX210745_RAM_WIDTH] mem_data_write_i,
    input      [1:0]        mem_size_i,

    output reg [`YSYX210745_REG_WIDTH] mtime_o,
    output reg [`YSYX210745_REG_WIDTH] mtimecmp_o,
    output                  clint_interrupt_o

);

   always @(posedge clk)
    begin
        if( rst == `YSYX210745_RST )begin
            mtime_o    <= 0;
            mtimecmp_o <= 0;
        end
        else if(clint_wr_i & mtime_ena_i)begin
            case(mem_size_i)
                `YSYX210745_SIZE_B : begin mtime_o    <= 64'hffff &mem_data_write_i;
                                mtimecmp_o <= mtimecmp_o;
                                end
                `YSYX210745_SIZE_H : begin mtime_o    <= 64'hfffffff &mem_data_write_i;
                                mtimecmp_o <= mtimecmp_o;
                                end
                `YSYX210745_SIZE_W : begin mtime_o    <= 64'hffff_ffffffff &mem_data_write_i;
                                mtimecmp_o <= mtimecmp_o;
                                end
                `YSYX210745_SIZE_D : begin mtime_o    <= 64'hffffffff_ffffffff &mem_data_write_i;
                                mtimecmp_o <= mtimecmp_o;
                                end
                default : begin mtime_o    <= mtime_o;
                                mtimecmp_o <= mtimecmp_o;
                                end
            endcase
        end 
        else if(clint_wr_i & mtimecmp_ena_i)begin
            case(mem_size_i)
                `YSYX210745_SIZE_B : begin mtime_o    <= mtime_o;
                                mtimecmp_o <= 64'hffff & mem_data_write_i;
                                end
                `YSYX210745_SIZE_H : begin mtime_o    <= mtime_o;
                                mtimecmp_o <= 64'hffffffff & mem_data_write_i;
                                end
                `YSYX210745_SIZE_W : begin mtime_o    <= mtime_o;
                                mtimecmp_o <= 64'hffff_ffffffff & mem_data_write_i;
                                end
                `YSYX210745_SIZE_D : begin mtime_o    <= mtime_o;
                                mtimecmp_o <= 64'hffffffff_ffffffff & mem_data_write_i;
                                end
                default : begin mtime_o    <= mtime_o;
                                mtimecmp_o <= mtimecmp_o;
                                end
            endcase
        end 
        else begin
            mtime_o    <= mtime_o + 1;
            mtimecmp_o <= mtimecmp_o;
        end
    end

    assign clint_interrupt_o = mtime_o >= mtimecmp_o;

    


endmodule



module ysyx_210745_csr_regfile(

    input  wire                  clk,
	input  wire                  rst,

    input  wire                  ecall_i,
    input  wire                  mret_i,
    input  wire [`YSYX210745_RAM_BUS]       pc_i,
    input  wire                  if_reg_valid_i,
    input  wire [`YSYX210745_RAM_BUS]       if_pc_i,
    input  wire                  clint_interrupt_i,  //csr_mtime >= csr_mtimecmp;

    input  wire [11:0]           csr_rd_addr,
    input  wire [11:0]           csr_wr_addr,
    input  wire                  csr_rd_ena,
    input  wire                  csr_wr_ena, 
    input  wire [`YSYX210745_REG_WIDTH]     csr_wr_data,

    output wire                  clint_o,
    output reg  [`YSYX210745_REG_WIDTH]     csr_rd_data,

    //output wire [`YSYX210745_REG_WIDTH]     mstatus_o,
    //output wire [`YSYX210745_REG_WIDTH]     mie_o,
    output wire [`YSYX210745_REG_WIDTH]     mtvec_o,
    output wire [`YSYX210745_REG_WIDTH]     mepc_o
    //output wire [`YSYX210745_REG_WIDTH]     mcause_o,
    //output wire [`YSYX210745_REG_WIDTH]     mtval_o,
    //output wire [`YSYX210745_REG_WIDTH]     mip_o,
    //output wire [`YSYX210745_REG_WIDTH]     medeleg_o,
    //output wire [`YSYX210745_REG_WIDTH]     mideleg_o,
    //output wire [`YSYX210745_REG_WIDTH]     mscratch_o,

    //output wire [`YSYX210745_REG_WIDTH]     sstatus_o
  
);
//csr machine  
    reg [62:0]       csr_mstatus; //{sd,csr_mstatus}
    reg [`YSYX210745_REG_WIDTH] csr_mie;
    reg [`YSYX210745_REG_WIDTH] csr_mtvec;
    reg [`YSYX210745_REG_WIDTH] csr_mepc;
    reg [`YSYX210745_REG_WIDTH] csr_mcause;
    reg [`YSYX210745_REG_WIDTH] csr_mtval;
    reg [`YSYX210745_REG_WIDTH] csr_mip;
    reg [`YSYX210745_REG_WIDTH] csr_medeleg;
    reg [`YSYX210745_REG_WIDTH] csr_mideleg;
    reg [`YSYX210745_REG_WIDTH] csr_mscratch;

//csr user 
    reg [`YSYX210745_REG_WIDTH] csr_mcycle;
    reg [`YSYX210745_REG_WIDTH] csr_minstret;
//clint
    wire clint_interrupt_valid;
    reg  mepc_ready;              // for clint interrupt

//mstatus
    wire       mie, mpie;
    //wire [1:0] mpp;
    wire sd;
    assign mie  = csr_mstatus[3];
    assign mpie = csr_mstatus[7];
    //assign mpp  = csr_mstatus[12:11]; 
    assign sd   = csr_mstatus[14:13] == 2'b11 | csr_mstatus[16:15] == 2'b11;

    //assign mstatus_o    =  {sd,csr_mstatus};
    //assign mie_o        =  csr_mie;
    assign mtvec_o      =  csr_mtvec;
    assign mepc_o       =  csr_mepc;
    //assign mcause_o     =  csr_mcause;
    //assign mtval_o      =  csr_mtval;
    //assign mip_o        =  csr_mip;
    //assign medeleg_o    =  csr_medeleg;
    //assign mideleg_o    =  csr_mideleg;
    //assign mscratch_o   =  csr_mscratch;
    //assign sstatus_o    =  mstatus_o & 64'h80000003_000DE122;

;

//clint interrupt

    assign clint_interrupt_valid = clint_interrupt_i & csr_mstatus[3] & csr_mie[7];
    assign clint_o               = clint_interrupt_valid & if_reg_valid_i && mepc_ready == 1'b1;

    always @(posedge clk)
    begin
        if( rst == `YSYX210745_RST )
            mepc_ready <= 1'b1;
        else if(clint_o) 
            mepc_ready <= 1'b0;
        else if(mret_i & mepc_ready == 1'b0)
            mepc_ready <= 1'b1;
        else
            mepc_ready <= mepc_ready;
    end

    always @(posedge clk) 
	begin
		if ( rst == `YSYX210745_RST ) 
		begin
            csr_mstatus     <=    63'b0;      //{51'b0,2'b11,11'b0}; //mpp特权模式写死为11
            csr_mie         <=    `YSYX210745_ZERO_WORD;
            csr_mtvec       <=    `YSYX210745_ZERO_WORD; //低两位写死为00
            csr_mepc        <=    `YSYX210745_ZERO_WORD;
            csr_mcause      <=    `YSYX210745_ZERO_WORD;
            csr_mtval       <=    `YSYX210745_ZERO_WORD;
            csr_mip         <=    `YSYX210745_ZERO_WORD;
            csr_mcycle      <=    `YSYX210745_ZERO_WORD;
            csr_minstret    <=    `YSYX210745_ZERO_WORD;
            csr_medeleg     <=    `YSYX210745_ZERO_WORD;
            csr_mideleg     <=    `YSYX210745_ZERO_WORD;
            csr_mscratch    <=    `YSYX210745_ZERO_WORD;
        end
        else if(clint_o)begin
            csr_mstatus     <=   {csr_mstatus[62:13],2'b11,csr_mstatus[10:8],mie,csr_mstatus[6:4],1'b0,csr_mstatus[2:0]};
            csr_mie         <=   csr_mie;
            csr_mtvec       <=   csr_mtvec;
            csr_mepc        <=   {if_pc_i[63:2],2'b0};
            csr_mcause      <=   64'h8000000000000007;
            csr_mtval       <=   csr_mtval;
            csr_mip         <=   csr_mip;
            csr_mcycle      <=   csr_mcycle;
            csr_minstret    <=   csr_minstret;
            csr_medeleg     <=   csr_medeleg;
            csr_mideleg     <=   csr_mideleg;
            csr_mscratch    <=   csr_mscratch;
        end
        else if(ecall_i)begin
            csr_mstatus     <=   {csr_mstatus[62:13],2'b11,csr_mstatus[10:8],mie,csr_mstatus[6:4],1'b0,csr_mstatus[2:0]};
            csr_mie         <=   csr_mie;
            csr_mtvec       <=   csr_mtvec;
            csr_mepc        <=   {pc_i[63:2],2'b0};
            csr_mcause      <=   11;
            csr_mtval       <=   csr_mtval;
            csr_mip         <=   csr_mip;
            csr_mcycle      <=   csr_mcycle;
            csr_minstret    <=   csr_minstret;
            csr_medeleg     <=   csr_medeleg;
            csr_mideleg     <=   csr_mideleg;
            csr_mscratch    <=   csr_mscratch;
        end
        else if(mret_i)begin
            csr_mstatus     <=   {csr_mstatus[62:13],2'b0,csr_mstatus[10:8],1'b1,csr_mstatus[6:4],mpie,csr_mstatus[2:0]};
            csr_mie         <=   csr_mie;
            csr_mtvec       <=   csr_mtvec;
            csr_mepc        <=   csr_mepc;
            csr_mcause      <=   csr_mcause;
            csr_mtval       <=   csr_mtval;
            csr_mip         <=   csr_mip;
            csr_mcycle      <=   csr_mcycle;
            csr_minstret    <=   csr_minstret;
            csr_medeleg     <=   csr_medeleg;
            csr_mideleg     <=   csr_mideleg;
            csr_mscratch    <=   csr_mscratch;
        end
        else if (csr_wr_ena)
            begin	
                case (csr_wr_addr) 
                    `YSYX210745_MSTATUS  : csr_mstatus   <=   csr_wr_data[62:0];
                    `YSYX210745_MIE      : csr_mie       <=   csr_wr_data;
                    `YSYX210745_MTVEC    : csr_mtvec     <=   csr_wr_data;
                    `YSYX210745_MEPC     : csr_mepc      <=   csr_wr_data;
                    `YSYX210745_MCAUSE   : csr_mcause    <=   csr_wr_data;
                    `YSYX210745_MTVAL    : csr_mtval     <=   csr_wr_data;
                    `YSYX210745_MIP      : csr_mip       <=   csr_wr_data;
                    `YSYX210745_MCYCLE   : csr_mcycle    <=   csr_wr_data;
                    `YSYX210745_MINSTRET : csr_minstret  <=   csr_wr_data;
                    `YSYX210745_MEDELEG  : csr_medeleg   <=   csr_wr_data;
                    `YSYX210745_MIDELEG  : csr_mideleg   <=   csr_wr_data;
                    `YSYX210745_MSCRATCH : csr_mscratch  <=   csr_wr_data;
                    default:
                    begin
                                csr_mstatus   <=   csr_mstatus;
                                csr_mie       <=   csr_mie;
                                csr_mtvec     <=   csr_mtvec;
                                csr_mepc      <=   csr_mepc;
                                csr_mcause    <=   csr_mcause;
                                csr_mtval     <=   csr_mtval;
                                csr_mip       <=   csr_mip;
                                csr_mcycle    <=   csr_mcycle;
                                csr_minstret  <=   csr_minstret;
                                csr_medeleg     <=   csr_medeleg;
                                csr_mideleg     <=   csr_mideleg;
                                csr_mscratch    <=   csr_mscratch;
                    end
                endcase
            end
        else
            begin
                                csr_mstatus   <=   csr_mstatus;
                                csr_mie       <=   csr_mie;
                                csr_mtvec     <=   csr_mtvec;
                                csr_mepc      <=   csr_mepc;
                                csr_mcause    <=   csr_mcause;
                                csr_mtval     <=   csr_mtval;
                                csr_mip       <=   csr_mip;
                                csr_mcycle    <=   csr_mcycle + 1'b1;
                                csr_minstret  <=   csr_minstret;
                                csr_medeleg     <=   csr_medeleg;
                                csr_mideleg     <=   csr_mideleg;
                                csr_mscratch    <=   csr_mscratch;
            end
				
		end
	
    always @(*) begin
		if (rst == `YSYX210745_RST)
			csr_rd_data = `YSYX210745_ZERO_WORD;
		else if (csr_rd_ena == 1'b1)
			case (csr_rd_addr) 
                `YSYX210745_MSTATUS  : csr_rd_data   =   {sd,csr_mstatus};
                `YSYX210745_MIE      : csr_rd_data   =   csr_mie;
                `YSYX210745_MTVEC    : csr_rd_data   =   csr_mtvec;
                `YSYX210745_MEPC     : csr_rd_data   =   csr_mepc;
                `YSYX210745_MCAUSE   : csr_rd_data   =   csr_mcause;
                `YSYX210745_MTVAL    : csr_rd_data   =   csr_mtval;
                `YSYX210745_MIP      : csr_rd_data   =   csr_mip;
                `YSYX210745_MCYCLE   : csr_rd_data   =   csr_mcycle;
                `YSYX210745_MINSTRET : csr_rd_data   =   csr_minstret;
                `YSYX210745_MEDELEG  : csr_rd_data   =   csr_medeleg;
                `YSYX210745_MIDELEG  : csr_rd_data   =   csr_mideleg;
                `YSYX210745_MSCRATCH : csr_rd_data   =   csr_mscratch;
                default   : csr_rd_data   =   `YSYX210745_ZERO_WORD;
            endcase
		else
			csr_rd_data = `YSYX210745_ZERO_WORD;
	end
      

endmodule




module ysyx_210745_data_ctr(

    input                       id_rs1_r_ena_i,
    input                       id_rs2_r_ena_i,

    input       [`YSYX210745_REG_BUS]      id_rs1_addr_i,
    input       [`YSYX210745_REG_BUS]      id_rs2_addr_i,

    input       [`YSYX210745_REG_WIDTH]    rs1_data_i,
    input       [`YSYX210745_REG_WIDTH]    rs2_data_i,


    input                       exe_w_ena_i,    
    input                       mem_w_ena_i,    
    input                       wb_w_ena_i,
    input       [`YSYX210745_REG_BUS]      exe_w_addr_i,
    input       [`YSYX210745_REG_BUS]      mem_w_addr_i,
    input       [`YSYX210745_REG_BUS]      wb_w_addr_i,
    input                       exe_data_valid_i,
    input                       mem_data_valid_i,
    input       [`YSYX210745_REG_WIDTH]    exe_w_data_i,
    input       [`YSYX210745_REG_WIDTH]    mem_w_data_i,
    input       [`YSYX210745_REG_WIDTH]    wb_w_data_i,


    output wire [`YSYX210745_REG_WIDTH]    id_rs1_data_o,
    output wire [`YSYX210745_REG_WIDTH]    id_rs2_data_o,
    output wire                 id_hit_o   // to drive id_stall 


);
    wire id_exe_rs1_hit, id_mem_rs1_hit, id_wb_rs1_hit;
    wire id_exe_rs2_hit, id_mem_rs2_hit, id_wb_rs2_hit;
    

    assign id_exe_rs1_hit  = (id_rs1_addr_i == exe_w_addr_i) & exe_w_ena_i & id_rs1_r_ena_i & exe_data_valid_i;
    assign id_exe_rs2_hit  = (id_rs2_addr_i == exe_w_addr_i) & exe_w_ena_i & id_rs2_r_ena_i & exe_data_valid_i;
    assign id_mem_rs1_hit  = (id_rs1_addr_i == mem_w_addr_i) & mem_w_ena_i & id_rs1_r_ena_i & mem_data_valid_i;
    assign id_mem_rs2_hit  = (id_rs2_addr_i == mem_w_addr_i) & mem_w_ena_i & id_rs2_r_ena_i & mem_data_valid_i;
    assign id_wb_rs1_hit   = (id_rs1_addr_i == wb_w_addr_i ) & wb_w_ena_i  & id_rs1_r_ena_i;
    assign id_wb_rs2_hit   = (id_rs2_addr_i == wb_w_addr_i ) & wb_w_ena_i  & id_rs2_r_ena_i;
    assign id_hit_o        = (id_rs1_addr_i == exe_w_addr_i) & exe_w_ena_i & id_rs1_r_ena_i |
                             (id_rs2_addr_i == exe_w_addr_i) & exe_w_ena_i & id_rs2_r_ena_i |
                             (id_rs1_addr_i == mem_w_addr_i) & mem_w_ena_i & id_rs1_r_ena_i |
                             (id_rs2_addr_i == mem_w_addr_i) & mem_w_ena_i & id_rs2_r_ena_i;

    assign id_rs1_data_o = id_exe_rs1_hit ? exe_w_data_i :
                           id_mem_rs1_hit ? mem_w_data_i :
                           id_wb_rs1_hit  ? wb_w_data_i  :
                           rs1_data_i;

    assign id_rs2_data_o = id_exe_rs2_hit ? exe_w_data_i :
                           id_mem_rs2_hit ? mem_w_data_i :
                           id_wb_rs2_hit  ? wb_w_data_i  :
                           rs2_data_i;
                        
endmodule



module ysyx_210745_regfile(
    input  wire clk,
	input  wire rst,
	
	input  wire  [`YSYX210745_REG_BUS]      w_addr,
	input  wire  [`YSYX210745_REG_WIDTH]    w_data,
	input  wire 		         w_ena,
	
	input  wire  [`YSYX210745_REG_BUS]      r_addr1,
	output reg   [`YSYX210745_REG_WIDTH]    r_data1,
	input  wire 		         r_ena1,
	
	input  wire  [`YSYX210745_REG_BUS]  	 r_addr2,
	output reg   [`YSYX210745_REG_WIDTH]    r_data2,
	input  wire 		  	     r_ena2

	//output reg   [`YSYX210745_REG_WIDTH]	 regs[0:31]      
    );

    reg   [`YSYX210745_REG_WIDTH]	 regs[0:31];
	
	always @(posedge clk) 
	begin
		if ( rst == `YSYX210745_RST ) 
		begin
			regs[ 0]      <=   `YSYX210745_ZERO_WORD;
			regs[ 1]      <=   `YSYX210745_ZERO_WORD;
			regs[ 2]      <=   `YSYX210745_ZERO_WORD;
			regs[ 3]      <=   `YSYX210745_ZERO_WORD;
			regs[ 4]      <=   `YSYX210745_ZERO_WORD;
			regs[ 5]      <=   `YSYX210745_ZERO_WORD;
			regs[ 6]      <=   `YSYX210745_ZERO_WORD;
			regs[ 7]      <=   `YSYX210745_ZERO_WORD;
			regs[ 8]      <=   `YSYX210745_ZERO_WORD;
			regs[ 9]      <=   `YSYX210745_ZERO_WORD;
			regs[10]      <=   `YSYX210745_ZERO_WORD;
			regs[11]      <=   `YSYX210745_ZERO_WORD;
			regs[12]      <=   `YSYX210745_ZERO_WORD;
			regs[13]      <=   `YSYX210745_ZERO_WORD;
			regs[14]      <=   `YSYX210745_ZERO_WORD;
			regs[15]      <=   `YSYX210745_ZERO_WORD;
			regs[16]      <=   `YSYX210745_ZERO_WORD;
			regs[17]      <=   `YSYX210745_ZERO_WORD;
			regs[18]      <=   `YSYX210745_ZERO_WORD;
			regs[19]      <=   `YSYX210745_ZERO_WORD;
			regs[20]      <=   `YSYX210745_ZERO_WORD;
			regs[21]      <=   `YSYX210745_ZERO_WORD;
			regs[22]      <=   `YSYX210745_ZERO_WORD;
			regs[23]      <=   `YSYX210745_ZERO_WORD;
			regs[24]      <=   `YSYX210745_ZERO_WORD;
			regs[25]      <=   `YSYX210745_ZERO_WORD;
			regs[26]      <=   `YSYX210745_ZERO_WORD;
			regs[27]      <=   `YSYX210745_ZERO_WORD;
			regs[28]      <=   `YSYX210745_ZERO_WORD;
			regs[29]      <=   `YSYX210745_ZERO_WORD;
			regs[30]      <=   `YSYX210745_ZERO_WORD;
			regs[31]      <=   `YSYX210745_ZERO_WORD;
		end
		else 
		begin
			if ((w_ena == 1'b1) && (w_addr != 5'h00))	
				regs[w_addr] <= w_data;
		end
	end
	
	always @(*) begin
		if (rst == `YSYX210745_RST)
			r_data1 = `YSYX210745_ZERO_WORD;
		else if (r_ena1 == 1'b1)
			r_data1 = regs[r_addr1];
		else
			r_data1 = `YSYX210745_ZERO_WORD;
	end
	
	always @(*) begin
		if (rst == `YSYX210745_RST)
			r_data2 = `YSYX210745_ZERO_WORD;
		else if (r_ena2 == 1'b1)
			r_data2 = regs[r_addr2];
		else
			r_data2 = `YSYX210745_ZERO_WORD;
	end


endmodule


//stall control unit

module ysyx_210745_scu(

    input              if_ready_i,
    input              mem_ready_i,
    input              mem_valid_i,
    input              id_branch_tag_i,
    input              id_hit_i,

    output wire [3:0]  stall_ena_o,   // [3:0] --> mem,exe,id,if
    output wire [3:0]  pipe_rst_o,
    output wire        mem_req_o
);

    wire if_req, id_req, exe_req, mem_req;
    wire if_stall, id_stall, exe_stall, mem_stall;
    wire if_rst, id_rst, exe_rst, mem_rst;

    assign stall_ena_o = {mem_stall,exe_stall,id_stall,if_stall};
    assign pipe_rst_o  = {mem_rst,exe_rst,id_rst,if_rst};
    assign mem_req_o   = mem_req;

    //stall_req
    assign if_req    = ~if_ready_i;
    assign id_req    = id_branch_tag_i & id_hit_i;
    assign exe_req   = 0;
    assign mem_req   = ~mem_ready_i & mem_valid_i;

    //stall
    assign if_stall  = id_req  | exe_req | mem_req;
    assign id_stall  = exe_req | mem_req;
    assign exe_stall = mem_req;
    assign mem_stall = 0;

    //rst
    assign if_rst    = if_req;
    assign id_rst    = id_req;
    assign exe_rst   = exe_req;
    assign mem_rst   = mem_req;




endmodule












